Compare commits

..
Author SHA1 Message Date
Hiroku 488f38c690 Merge branch 'removable-features' into 'main'
Adds the ability to hide certain features from rendering in the StatsWidget.

See merge request cable-mc/cobblemon!1914
2025-11-14 12:39:40 +00:00
Landon d1b7dc6934 Merge branch 'making-pi-equal-3' into 'main'
Fix major camera issues.

See merge request cable-mc/cobblemon!1972
2025-11-14 06:58:05 +00:00
JPAKx4 282bb4784e Accessor grabs the wrong forwards (FORWARDS vs forwards, what is this VIM?) so make it not do that. Fixes the major camera issues from the last two days. 2025-11-14 00:10:24 -06:00
Hiroku a8267b8ee0 Merge branch 'molang-oh-molang' into 'main'
Removed the additional DoubleValue in seen_credits and is_in_dialogue

See merge request cable-mc/cobblemon!1971
2025-11-14 05:00:28 +00:00
Spicy 81f36b2b15 Removed the additional DoubleValue in seen_credits and is_in_dialogue 2025-11-13 22:49:10 -06:00
Hiroku 73e96740d6 Merge branch 'something-funny-and-creative-dot-mp4' into 'main'
Add 180deg rotation, I should test better for sure.

See merge request cable-mc/cobblemon!1970
2025-11-14 04:06:23 +00:00
JPAKx4 d53f9e5c63 Add 180deg rotation, I should test better for sure. 2025-11-13 21:20:11 -06:00
Hiroku 560bd75fd0 Merge branch 'fix/vanilla-connection' into 'main'
fix: fix vanilla connection with the cobblemon mods

See merge request cable-mc/cobblemon!1969
2025-11-14 02:30:25 +00:00
Paul 8850d38820 Rescraped behaviours to amend swim ability 2025-11-14 11:18:23 +10:00
terrainwax 34232b33c7 fix: fix vanilla connection with the cobblemon mods 2025-11-13 22:30:12 +01:00
Landon 03c5a34fc8 Merge branch 'mixin-fix' into 'main'
Avoid relying on local player in common mixin

See merge request cable-mc/cobblemon!1968
2025-11-13 17:29:19 +00:00
Landon Wills 866db3d350 Avoid relying on local player in common mixin 2025-11-13 11:44:02 -05:00
Landon ee51a8a34b Merge branch 'more-misc-additions' into 'main'
More misc additions

See merge request cable-mc/cobblemon!1950
2025-11-13 13:18:32 +00:00
Deltric 2769733c51 More misc additions 2025-11-13 13:18:32 +00:00
Landon 8ae79d8e44 Merge branch 'jackowes-riding-fixes' into 'main'
various riding bug fixes

See merge request cable-mc/cobblemon!1966
2025-11-13 09:28:17 +00:00
Hiroku 6f08d610eb Merge branch 'we-dont-hang-anymore' into 'main'
Fixes Fabric server hanging on shutdown while players are logged in

See merge request cable-mc/cobblemon!1964
2025-11-13 09:19:04 +00:00
Hiroku 75f3db16aa Merge branch 'more-poke-snack-stuff' into 'main'
More Poké Snack stuff

Closes #1761

See merge request cable-mc/cobblemon!1931
2025-11-13 09:11:53 +00:00
Hiroku e4ee6b29ab Merge branch 'remove-shadow-people' into 'main'
Remove shadow people from appearing on mounts

See merge request cable-mc/cobblemon!1967
2025-11-13 09:08:42 +00:00
Watuneni iteite cb6b2b9ec5 Translated using Weblate (Japanese)
Currently translated at 94.3% (8447 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-13 09:07:00 +00:00
geumu 8eafe14f66 Translated using Weblate (Korean)
Currently translated at 61.5% (5513 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-13 09:07:00 +00:00
Paul 8176e14981 Merge remote-tracking branch 'weblate/lang-updates' 2025-11-13 19:05:24 +10:00
Paul 7d956500f2 Scraped behaviours 2025-11-13 19:04:55 +10:00
Landon Wills c6853b84a6 Remove shadow people from appearing on mounts 2025-11-13 03:58:59 -05:00
Polymeta 3cb4984d51 Merge branch 'shine-bright-like-an-evo-stone' into 'main'
Update Lighting Values

See merge request cable-mc/cobblemon!1951
2025-11-13 07:30:10 +00:00
dhi_holo 930ed59234 Update Lighting Values 2025-11-13 07:30:10 +00:00
jackowes 3ea1918bc2 - Fix hand rotations on mount. The mixin that fixes it wasn't adjusted for the orientation refactor. 2025-11-13 00:55:11 -06:00
jackowes 1dee9bc630 - Move game pause orientation protections to only the lerp factor. This is to prevent camera lerping while the game is paused. It was previously at the top of the setRotations CameraMixin function which would convert you back to vanilla rotations when paused.
- clamp local rideXrotations
- Fix player head rotations while riding.
- Lessen upwards boost on takeoff
2025-11-12 23:09:06 -06:00
Landon d761f2b4dc Merge branch 'riding-go-brr' into 'main'
Many Riding Fixes

See merge request cable-mc/cobblemon!1963
2025-11-13 04:56:11 +00:00
Test 0d6028706d Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2025-11-12 23:15:25 -05:00
Test 63d6851482 disable sacch dispenser interaction for now 2025-11-12 23:15:04 -05:00
Apion 7c3158c63b Merge branch 'particle-sounds-1.7' into 'main'
Refactored move sound file names, added all new move sounds

See merge request cable-mc/cobblemon!1965
2025-11-13 00:35:43 +00:00
Teggy e9e41933fe Translated using Weblate (Spanish)
Currently translated at 84.6% (7578 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-11-13 00:30:11 +00:00
Nico Merenq 7c7fd6c982 Translated using Weblate (Russian)
Currently translated at 75.4% (6757 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-13 00:30:09 +00:00
geumu 6ec2820dd8 Translated using Weblate (Korean)
Currently translated at 59.9% (5367 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-13 00:30:07 +00:00
321retrogamer b1054bdf11 Various move-related Sound and Action effect tweaks.
Fixes timing for various Action Effects to better fit their sound design. Additionally, updates sounds for Infestation and Ice Beam and re-adds Ember and Flamethrower sound cues to their respective Action Effects.
2025-11-12 17:49:38 -06:00
Neovitalism 3b227ba3a2 Fixes fabric server hanging on shutdown 2025-11-12 16:01:01 -06:00
JPAKx4 96049abb98 Fix Merge issues 2025-11-12 15:20:36 -06:00
JPAKx4 d661e88a96 Merge branch 'main' into riding-go-brr 2025-11-12 15:19:25 -06:00
Apion 8510e05177 Remove redundant local field in MountedCameraRenderer.kt 2025-11-12 16:13:56 -05:00
JPAKx4 af4fe4d09d Merge branch 'main' into riding-go-brr
# Conflicts:
#	common/src/main/java/com/cobblemon/mod/common/mixin/client/CameraMixin.java
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/camera/MountedCameraRenderer.kt
2025-11-12 14:09:14 -06:00
Apion 8b2ffd0f29 Merge branch 'apion-bugfix' into 'main'
Fix bug with camera mixin on NeoForge

See merge request cable-mc/cobblemon!1956
2025-11-12 19:57:34 +00:00
Apion 18cebc794b Clean up variable names in CameraMixin 2025-11-12 14:11:14 -05:00
Apion 64e84dab64 Merge remote-tracking branch 'origin/main' into apion-bugfix
# Conflicts:
#	common/src/main/java/com/cobblemon/mod/common/mixin/client/CameraMixin.java
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/camera/MountedCameraRenderer.kt
2025-11-12 13:21:18 -05:00
JPAKx4 9c5535a014 Fix offsets being rotated and offsets being applied twice. Changed default third person offset (negotiable, no idea good values). Fix no view bobbing. Add dismount location logic from horses, might need more testing or accounting for other mount types. 2025-11-12 12:02:03 -06:00
Nico Merenq 5993c1e588 Translated using Weblate (Russian)
Currently translated at 71.8% (6433 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-12 16:40:16 +00:00
geumu e8f7983dd2 Translated using Weblate (Korean)
Currently translated at 59.5% (5338 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-12 16:40:14 +00:00
Watuneni iteite bdd172bd2d Translated using Weblate (Japanese)
Currently translated at 94.2% (8446 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-12 16:40:12 +00:00
Paul 13842de7d6 Merge remote-tracking branch 'origin/main' 2025-11-12 23:26:31 +10:00
Paul f05e059445 Lil fixes oopsy 2025-11-12 23:26:22 +10:00
Polymeta 038d9e858c Merge branch 'mechanics-sync' into 'main'
Mechanics sync

See merge request cable-mc/cobblemon!1960
2025-11-12 13:12:49 +00:00
lion 9913826e24 Mechanics sync 2025-11-12 13:12:49 +00:00
Polymeta 8f971cc3d6 Merge branch '1.7-spawns-update' into 'main'
Updated all spawn files. Changed dead_coral preset into a block tag.

See merge request cable-mc/cobblemon!1962
2025-11-12 11:38:03 +00:00
Veraxiel 33c74372a4 Updated all spawn files. Changed dead_coral preset into a block tag. 2025-11-12 05:48:29 -05:00
Polymeta 5f11f4bdd6 Merge branch 'Saccharine-Tree-Biome-List-Update' into 'main'
Updated biome list for saccharine tree

See merge request cable-mc/cobblemon!1959
2025-11-12 09:55:01 +00:00
Polymeta 13b4bdc204 Merge branch 'SaccHiveGenerationRebalance' into 'main'
SaccHiveGenerationRebalance

See merge request cable-mc/cobblemon!1961
2025-11-12 09:54:49 +00:00
Paul 451ae00da1 Drops scrape 2025-11-12 19:11:39 +10:00
Paul a8cc8278d3 Liechi berry should target the right biome 2025-11-12 18:57:03 +10:00
Landon 58c0136ad1 Merge branch 'quick-misc-additions' into 'main'
Misc Changes

See merge request cable-mc/cobblemon!1941
2025-11-12 06:39:48 +00:00
Deltric 45238058cb Misc Changes 2025-11-12 06:39:47 +00:00
JPAKx4 a326befcef Fix offsets being rotated and offsets being applied twice 2025-11-11 22:38:43 -06:00
JazzMcNade 52d8887514 Natural trees increased to 50% hives, Grown trees increased to 10% hives 2025-11-11 20:45:24 -06:00
Test 02ae8065ac Set duration for displaying ride controls in config to 0 by default 2025-11-12 01:43:01 +00:00
Slippy c37c608010 Updated biome list for saccharine tree 2025-11-11 18:27:42 -06:00
Nico Merenq 09c4ae96bf Translated using Weblate (Russian)
Currently translated at 70.9% (6352 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-11 22:50:22 +00:00
Nick be466d1610 Merge branch 'aprijuice-neoforge-crash-fix' into 'main'
Fix Aprijuices crashing on Neoforge

See merge request cable-mc/cobblemon!1957
2025-11-11 11:18:42 -08:00
lion d75faae1a0 Fix Aprijuices crashing on Neoforge 2025-11-11 11:18:42 -08:00
Guilherme Pereira 367264b06e Merge branch 'main' of gitlab.com:cable-mc/cobblemon into more-poke-snack-stuff 2025-11-11 14:52:37 -03:00
Guilherme Pereira 3631fa909d Merge branch 'more-poke-snack-stuff' of gitlab.com:cable-mc/cobblemon into more-poke-snack-stuff 2025-11-11 14:51:41 -03:00
Guilherme Pereira fc29826bc7 fix cakes not being rendered properly on multiplayer 2025-11-11 14:51:18 -03:00
Polymeta 202bee5690 Merge branch 'do-you-get-the-joke' into 'main'
🍆

See merge request cable-mc/cobblemon!1777
2025-11-11 17:03:40 +00:00
Landon 730dc88ede Merge branch 'small-rides-sprint-issue' into 'main'
fix the stuttery walk on large mons when ridden

See merge request cable-mc/cobblemon!1953
2025-11-11 15:17:21 +00:00
Landon 4f0a667f23 Merge branch 'riding-air-transition-improvement' into 'main'
Improve air transition so you can consistently get off the ground

See merge request cable-mc/cobblemon!1954
2025-11-11 15:17:01 +00:00
Landon f1186f469c Merge branch 'motion-sick-camera-changes' into 'main'
Motion Sick Cam

See merge request cable-mc/cobblemon!1948
2025-11-11 15:11:45 +00:00
Jackson Bowes 91eeecf6e4 Motion Sick Cam 2025-11-11 15:11:45 +00:00
Polymeta f6cae9d52e Edit eggantberry.js 2025-11-11 15:08:04 +00:00
Polymeta ed94d76e98 Merge branch '1.7-spawns' into 'main'
Added and updated spawns and tags. Edited berry data scraper.

See merge request cable-mc/cobblemon!1937
2025-11-11 15:04:46 +00:00
Polymeta 6e2b76d6a1 Merge branch 'its-not-bait' into 'main'
Bait Seasoning Correction

See merge request cable-mc/cobblemon!1955
2025-11-11 15:03:28 +00:00
Landon 2b70b222df Merge branch 'non-rolling-block-placement-fix' into 'main'
Fix non rollables arrow spawning and block picking. (building should be much better now)

See merge request cable-mc/cobblemon!1943
2025-11-11 14:51:18 +00:00
Landon e9f0ef6497 Merge branch 'camera-fixes' into 'main'
Camera fixes

See merge request cable-mc/cobblemon!1944
2025-11-11 14:41:24 +00:00
geumu 8fb93dd488 Translated using Weblate (Korean)
Currently translated at 55.2% (4949 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-11 08:19:44 +00:00
Neovitalism b863554c84 Changed to use the aspects of the pokémon instead of a new field. 2025-11-11 00:14:48 -06:00
Neovitalism 699d6fea17 Revert "Removable Feature Rendering"
This reverts commit d117d79d28.
2025-11-11 00:08:34 -06:00
dhi_holo a4dd34235a Bait Seasonings are now also Baits
Added Apple, Gapple, EGapples, Golden Carrots, and Glistering Melon Slices to the bait types
2025-11-11 15:37:08 +10:00
dhi_holo 8501fd3b18 Delete nether_star.json
Dev tester or something?
2025-11-11 14:36:19 +10:00
dhi_holo 52896b208e Bait Seasoning Correction
You can no longer cook Nether Stars into food, but you can Apples!
2025-11-11 14:28:43 +10:00
jackowes 6ad6487dbe Gave a bit more time to double jump and now boost the y velocity to a minimum of 0.4 on transition. 2025-11-10 21:30:37 -06:00
Nico Merenq 2cd066a4c1 Translated using Weblate (Russian)
Currently translated at 69.5% (6233 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-11 03:11:09 +00:00
jackowes 703ccb9d8e revert uneeded stuff 2025-11-10 19:34:53 -06:00
jackowes c33d4b591e fix the stuttery walk on large mons when ridden. The ridevelocity keeps going to zero at some point and I have no idea why. 2025-11-10 18:32:55 -06:00
Landon e31f2a2598 Merge branch 'small-rides-sprint-issue' into 'main'
Fix small mounts erratically stopping their sprints

See merge request cable-mc/cobblemon!1952
2025-11-10 23:37:03 +00:00
Nico Merenq 68b44db35c Translated using Weblate (Russian)
Currently translated at 67.3% (6032 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-10 22:22:58 +00:00
jackowes 513c958da1 Move sprint logic to custom tracking rather than using player sprint flag (odd interactions with short mounts) 2025-11-10 15:47:39 -06:00
Nico Merenq 18d3fb288a Translated using Weblate (Russian)
Currently translated at 65.7% (5885 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-10 19:28:47 +00:00
Weblate 725b4b7e48 Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/
2025-11-10 18:19:35 +00:00
geumu 28ae27b926 Translated using Weblate (Korean)
Currently translated at 55.2% (4949 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-10 18:19:31 +00:00
Watuneni iteite 21e9e73eee Translated using Weblate (Japanese)
Currently translated at 94.2% (8446 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-10 18:19:29 +00:00
Nico Merenq 6bfb318e2d Translated using Weblate (Russian)
Currently translated at 65.6% (5882 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-10 18:19:28 +00:00
Polymeta 9e1fde04ef Merge branch 'mopping-up-tags' into 'main'
Tags and Seasonings Improvement

Closes #1765 and #1764

See merge request cable-mc/cobblemon!1949
2025-11-10 09:30:10 +00:00
dhi_holo 6e4565d49b Update eggant_sprout.json
Missed a spot that didn't show up properly
2025-11-10 16:10:13 +10:00
dhi_holo 91f1523ef5 Update eggant_sprout.json
apparently the model didn't get updated properly
2025-11-10 15:59:09 +10:00
dhi_holo e949626f06 Update eggant_sprout.png
Mipmap Fix Compat
2025-11-10 15:26:32 +10:00
dhi_holo 9678fcc009 Merge branch 'main' into do-you-get-the-joke 2025-11-10 15:24:38 +10:00
dhi_holo 4fbe3e406d Merge branch 'main' into mopping-up-tags 2025-11-10 15:22:21 +10:00
dhi_holo 00a1e77a9f Update pitcher_plant.json
Buffed it
2025-11-10 15:20:28 +10:00
dhi_holo e055dede73 Number fix
Forgot it's in ticks not seconds.
2025-11-10 15:14:14 +10:00
Test b7550f7699 overlay texture 2025-11-09 23:36:55 -05:00
Test 98cfa0ac91 Merge branch 'mip-map-fix' into 'main'
Mip map fix

See merge request cable-mc/cobblemon!1707
2025-11-10 03:47:48 +00:00
Deltric f2441e7b27 Mip map fix 2025-11-10 03:47:48 +00:00
dhi_holo 46c247c742 Merge branch 'main' into mopping-up-tags 2025-11-10 13:28:49 +10:00
Guilherme Pereira 9770d8ca6b Merge branch 'main' of gitlab.com:cable-mc/cobblemon into more-poke-snack-stuff 2025-11-10 00:28:24 -03:00
Watuneni iteite 04c3e182e7 Translated using Weblate (Japanese)
Currently translated at 93.5% (8376 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-10 02:50:43 +00:00
Paul 3d99db64b9 Double the spawning speed for poke snack blocks 2025-11-10 12:39:10 +10:00
Test bbcfe95bac cake block, tinting updates 2025-11-09 21:03:50 -05:00
Paul 4f07746355 Fix poor failure handling in behaviours on NPCs. Closes #1772 2025-11-10 11:58:00 +10:00
Watuneni iteite 82088651c2 Translated using Weblate (Japanese)
Currently translated at 92.7% (8312 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-10 01:39:38 +00:00
Hiroku 2f0a201cf1 Merge branch 'aprijuice-color-crash' into 'main'
Aprijuice Color Crash

See merge request cable-mc/cobblemon!1946
2025-11-09 22:46:23 +00:00
Gertimoshka 778f24acf1 Fixed a bug where if there is no flavours in aprijuice, it would crash when rendered 2025-11-09 22:32:07 +02:00
geumu e3ead8e3e5 Translated using Weblate (Korean)
Currently translated at 50.4% (4515 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-09 19:29:48 +00:00
Nico Merenq 9c4b9b35ab Translated using Weblate (Russian)
Currently translated at 65.6% (5880 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-09 19:29:46 +00:00
jackowes aa9c7b4f55 Fix non rollables arrow spawning and block picking. (building should be much better now) 2025-11-09 10:39:13 -06:00
JPAKx4 96e2e4a6fe Merge remote-tracking branch 'origin/camera-fixes' into pivot
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/camera/MountedCameraRenderer.kt
2025-11-09 06:58:34 -06:00
JPAKx4 20d903cffe Fix some camera code that got yeeted in the cleanup. 2025-11-09 06:57:33 -06:00
JPAKx4 d4383fa317 Fix some camera code that got yeeted in the cleanup. 2025-11-09 06:47:41 -06:00
Paul 1687fa12db Changelog [skip-ci] 2025-11-09 22:11:19 +10:00
Hiroku cf599de339 Merge branch 'YetMorePathingImprovement' into 'main'
YetMorePathingImprovements

Closes #1754

See merge request cable-mc/cobblemon!1942
2025-11-09 12:09:38 +00:00
Hiroku c5f92c1ad4 Merge branch 'party-ui-overhaul' into 'main'
Implementation of Party Overlay UI Animations for different Events

See merge request cable-mc/cobblemon!1939
2025-11-09 12:08:38 +00:00
Paul 1d99da78e0 Updated the behaviour scraper 2025-11-09 21:35:33 +10:00
dhi_holo 050a2a6a4b Seasoning Fixes
Resolves #1765
Partially Addresses #1766
2025-11-09 15:25:02 +10:00
dhi_holo c80e7f4a51 Update leaves.json
Corrects IDs
Resolves #1764
2025-11-09 15:11:51 +10:00
dhi_holo f4fbdf8735 Block Tag Improvements
Added some overlooked pieces to certain tags
2025-11-09 15:03:43 +10:00
JPAKx4 ae6091fc01 Pull code out of the mixins. 2025-11-08 22:51:31 -06:00
dhi_holo f2aa4141c0 Merge branch 'main' into do-you-get-the-joke 2025-11-09 14:04:39 +10:00
Landon aeded69b25 Merge branch 'implement_pokemon' into 'main'
Merge species updates

See merge request cable-mc/cobblemon!1940
2025-11-09 02:59:41 +00:00
dhi_holo 16b25a2e6e Tag Updates
Now matches to main
2025-11-09 12:57:52 +10:00
dhi_holo e66ebfb7a8 Merge branch 'main' into do-you-get-the-joke 2025-11-09 12:56:25 +10:00
JazzMcNade 70e79e6fe4 Fix a case in which trimpath would result in a mon pathing into a solid block. Fixed NPCs getting stuck on specific upward diagonal formations 2025-11-08 20:20:47 -06:00
Tyzillion b905888a0b Gust more like fart. 2025-11-08 20:17:23 -05:00
Tyzillion 5917e52ffc >.> 2025-11-08 20:01:05 -05:00
Tyzillion deb20cb418 Refactored move sound file names to match repo, Implemented Gust,
Added sounds to:
acid, aerialace, bodyslam, bubble, bubblebeam, bulldoze, bulletpunch, closecombat, eruption, gust, icebeam, infestation, lavaplume, magicalleaf, mist, mudbomb, powdersnow, razorleaf, shadowball, sludgebomb, thunder, thunderbolt, thundershock, watergun, waterpulse, and willowisp.
2025-11-08 19:53:02 -05:00
Hiroku 797e0704e9 Merge branch 'new-aprijuice-point-formula' into 'main'
Aprijuice formula rework and don't allow poke bait to stack otherwise fishing combines baits and that's bad

See merge request cable-mc/cobblemon!1938
2025-11-09 00:24:56 +00:00
Carmendar 0b184a722b Cutiefly and Ribombee scale adjustments. 2025-11-08 18:17:35 -06:00
Carmendar 1a34c2942f Cutiefly line remodels and Charizard zfighting fix. 2025-11-08 17:29:16 -06:00
Carmendar 2a20398b42 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-08 15:25:42 -06:00
Apion 929e4b2391 Licenses 2025-11-08 15:43:50 -05:00
Carmendar 3931295086 Merge branch 'main' into implement_pokemon 2025-11-08 14:18:46 -06:00
Apion c593a8b7e6 Fixed CameraMixin on neoforge 2025-11-08 15:00:22 -05:00
Apion d0fc166e09 Fix SoundEngineMixin on neoforge 2025-11-08 14:44:33 -05:00
geumu 78f752b4a1 Translated using Weblate (Korean)
Currently translated at 48.7% (4366 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-08 19:29:08 +00:00
Apion b4c971398d Fix BrewingStandMenuMixin on neoforge 2025-11-08 14:01:02 -05:00
geumu f0f78a01e0 Translated using Weblate (Korean)
Currently translated at 48.7% (4366 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-08 18:16:24 +00:00
geumu 8c36ee15cd Translated using Weblate (Korean)
Currently translated at 48.6% (4355 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-08 16:54:27 +00:00
阿鱼 3231d97cd3 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (8957 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-08 16:54:26 +00:00
Nico Merenq 9fce4d3b6b Translated using Weblate (Russian)
Currently translated at 64.7% (5801 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-08 16:54:25 +00:00
violet 550e579190 e 2025-11-08 06:03:40 -05:00
violet e7d710e0a3 implemented poltchageist & sinistcha remodels (+ tweaks to polteageist) 2025-11-08 06:02:08 -05:00
violet acb86b1935 implemented dratini, dragonair, and dragonite remodels 2025-11-08 05:50:42 -05:00
Carmendar fd8e9b49b5 Adjusted some ride stats. 2025-11-08 03:07:34 -06:00
阿鱼 0f031545c1 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.1% (8877 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-08 08:30:14 +00:00
Landon Wills 1fdbee91df Run scraper 2025-11-08 03:10:01 -05:00
geumu 2b80189a79 Translated using Weblate (Korean)
Currently translated at 46.9% (4208 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-08 07:59:51 +00:00
geumu 2e88b0194e Translated using Weblate (Korean)
Currently translated at 46.6% (4176 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-08 06:51:21 +00:00
Nico Merenq b0e278d1a7 Translated using Weblate (Russian)
Currently translated at 63.3% (5674 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-08 06:51:12 +00:00
geumu 9c646d9d53 Translated using Weblate (Korean)
Currently translated at 46.6% (4174 of 8957 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-08 06:51:10 +00:00
Gertimoshka bfab1d7070 Actually Fix the Merge Conflicts 2025-11-07 16:41:39 +02:00
Gertimoshka e61e1390cb Fix Merge Conflicts 2025-11-07 14:26:09 +00:00
Gertimoshka 18151ff2f0 Implemented Levelup Sounds 2025-11-07 16:04:17 +02:00
Guilherme Pereira dd19140a83 change mark chance effect to drops reroll 2025-11-07 10:33:54 -03:00
Paul d5b1dfa9da no wait don't do that 2025-11-07 22:34:26 +10:00
Paul 9f0ddf4dd3 Put the bucket multiplication back onto fishing since I think I forgor to put this back on 2025-11-07 22:07:41 +10:00
Paul ef3ea62ae0 Aprijuice formula rework and don't allow poke bait to stack otherwise fishing combines baits and that's bad 2025-11-07 21:46:20 +10:00
Polymeta 6b43bf9f48 Merge branch 'main' into '1.7-spawns'
# Conflicts:
#   common/src/main/resources/data/cobblemon/spawn_pool_world/0194_wooper.json
#   common/src/main/resources/data/cobblemon/tags/worldgen/biome/is_mirage_island.json
#   utilityscripts/cobblemon_spawn_csv_to_json.py
2025-11-07 11:13:38 +00:00
Veraxiel a4012895f3 Added and updated spawns and tags. Edited berry data scraper. 2025-11-07 04:32:20 -05:00
FrankTheFarmer 7f6a3e8e87 Retweaked Alolan Golem's profile because the profile's respect aspects again. Yippee 2025-11-07 19:06:56 +10:00
FrankTheFarmer 7a84ea723f Merge branch 'main' into implement_pokemon 2025-11-07 18:53:53 +10:00
FrankTheFarmer 2aad33ded5 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-07 18:45:53 +10:00
Carmendar 254c95fa15 Rocket Expression changes. 2025-11-07 02:14:07 -06:00
Carmendar 5aab7f67e1 Ride anims for Lapras and Glide/Dive anims for Salamence. - surfacewater poser tweaks for some pokemon. - Tyrantrum crash fix. 2025-11-07 02:12:46 -06:00
Polymeta ae4decacc7 Merge branch 'bottle-o-knowledge' into 'main'
Added Unlock Condition

See merge request cable-mc/cobblemon!1936
2025-11-07 07:01:59 +00:00
dhi_holo ae5a9be626 Added Unlock Condition
Elixirs, Ethers, Potions, Super Potions, and Hyper Potions now unlock from having the berry or Medicinal Brew, rather than just the berry
2025-11-07 16:11:11 +10:00
Landon 05faea4ec8 Merge branch 'no-riding-suffocation' into 'main'
Prevent suffocation when riding a pokemon

See merge request cable-mc/cobblemon!1935
2025-11-07 05:09:05 +00:00
Landon Wills 05edd34db6 Prevent suffocation when riding a pokemon 2025-11-06 10:54:39 -05:00
Landon c198f8fccd Merge branch 'implement_pokemon' into 'main'
A more polished world...

See merge request cable-mc/cobblemon!1930
2025-11-06 14:37:53 +00:00
Landon Wills 521f9aaafa Scrape files 2025-11-06 08:52:29 -05:00
Hiroku 8d38505993 Merge branch 'SaccTreeFixes' into 'main'
SaccTreeFixes

See merge request cable-mc/cobblemon!1932
2025-11-06 12:20:44 +00:00
Carmendar 7c5fab02a8 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-06 01:53:24 -06:00
Carmendar 7e5a267c89 Dolphins & Submarines ready for business. - Mime Jr shoulder mount anims. - Various seats and poser tweaks. 2025-11-06 01:52:51 -06:00
Landon 5b23b0cfbe Merge branch 'pondering-my-orb-and-not-crashing' into 'main'
Fix a crash with Ponder and likely others in CameraMixin

See merge request cable-mc/cobblemon!1933
2025-11-05 13:52:17 +00:00
Nadja Reitzenstein 778ceff183 Fix a crash with Ponder and likely others in CameraMixin
Our setRotation mixin assumes the camera to be attached to an entity. It's not always, and it's not for Ponder Scenes specifically.
2025-11-05 13:57:36 +01:00
Paul f32050c8b5 Added setter to player spawner mixin and opened PlayerSpawner 2025-11-05 21:40:09 +10:00
Hiroku 3522bac72a Merge branch 'smeargle-paint-me-like-one-of-your-french-mooshtanks' into 'main'
Smeargle paint me like one of your french mooshtanks

See merge request cable-mc/cobblemon!1746
2025-11-05 11:24:27 +00:00
Paul ecf037666f Merge remote-tracking branch 'weblate/lang-updates' 2025-11-05 21:13:23 +10:00
Watuneni iteite 618d062ca9 Translated using Weblate (Japanese)
Currently translated at 93.5% (8334 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-05 11:13:04 +00:00
Paul 49841b40ec Merge remote-tracking branch 'weblate/lang-updates' 2025-11-05 21:10:49 +10:00
Paul 87141e1137 Variable naming cleanup 2025-11-05 21:09:18 +10:00
Paul 1f962d664f Removed inaccurate comment 2025-11-05 21:08:50 +10:00
Paul 09797f25b1 Added characteristic_rainbow molang function to pokemon behaviour object 2025-11-05 21:08:31 +10:00
Paul 3911413c69 Removed unused lang function 2025-11-05 21:08:09 +10:00
violet e075e60231 tea time 2025-11-05 05:35:57 -05:00
violet acdd98573b Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-05 05:27:35 -05:00
Paul 12f3e7b78b Fix party renders not respecting aspects 2025-11-05 19:01:24 +10:00
violet a462fe5efc added raboot.json poser 2025-11-05 03:43:26 -05:00
Carmendar 2390662fc8 A few submarines and poser/anim tweaks for Dusknoir, Bastiodon and Magnezone. Added surface water ride sounds for Aqua Tauros. 2025-11-05 02:33:26 -06:00
Carmendar 1bd5d2372f Merge branch 'refs/heads/main' into implement_pokemon
# Conflicts:
#	common/src/main/resources/data/cobblemon/species/generation4/garchomp.json
2025-11-05 01:20:44 -06:00
Landon Wills 12f6bb55c2 Fix goof 2025-11-05 02:05:32 -05:00
Landon fdb37ba5e8 Merge branch 'dolphin-sub-noPuke' into 'main'
submarine, dolphin rework, projectile support, view vector fix, and motion sick cam

See merge request cable-mc/cobblemon!1929
2025-11-05 06:56:07 +00:00
Jackson Bowes 7a99845d0f submarine, dolphin rework, projectile support, view vector fix, and motion sick cam 2025-11-05 06:56:06 +00:00
JazzMcNade 54d183c8d3 Merge branch 'main' into SaccTreeFixes 2025-11-04 23:08:44 -06:00
JazzMcNade 29713bbe1f Update SaccharineTreeFeature.kt
natural sacc trees have 20% chance to generate a hive.
post generation sacc trees with nearby flowers have 5% chance to generate a hive.
Hives now always generate adjacent to a log block.
No longer records flower positions.
2025-11-04 22:56:43 -06:00
Landon 247052ee67 Merge branch 'moonrise-compat' into 'main'
Retain moonrise compatibility for Cobblemon 1.7

See merge request cable-mc/cobblemon!1926
2025-11-05 03:11:05 +00:00
FrankTheFarmer 14b7e93965 Tweaked Geodude's look range + poser tweaks 2025-11-05 09:24:32 +10:00
FrankTheFarmer 85a4793a1e formatting and cry fix for Graveler and Golem posers 2025-11-05 09:23:32 +10:00
Veraxiel 29f6524c49 Fix to formatting in TimeRange.kt 2025-11-04 17:50:24 -05:00
Veraxiel 1e617a684b Minor edit to a time range in TimeRange.kt 2025-11-04 17:49:42 -05:00
Paul c9a0352a7c Nerfed aprijuice stat point gain, tweak saccharine tree top leaf gen 2025-11-05 06:40:51 +10:00
Gertimoshka 1a5808e5a6 Update Licenses 2025-11-04 21:57:53 +02:00
Gertimoshka f14d242907 Fix a crash in code for party overlay 2025-11-04 21:52:50 +02:00
Sterrezo 4998ee2c5b Added levelup sounds 2025-11-04 20:25:19 +01:00
Guilherme Pereira be96e45c4e change colors variable name 2025-11-04 08:41:42 -03:00
violet 015402d54b Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-04 05:24:23 -05:00
violet 6f697d2b9a solosis line poser tweaks 2025-11-04 05:23:29 -05:00
violet f18752d484 haxorus model + poser tweaks 2025-11-04 04:53:53 -05:00
violet 5876c02d44 unown animations 2025-11-04 04:28:56 -05:00
violet c890f6910c a lot of poser alterations 2025-11-04 04:27:24 -05:00
Paul d157536e1e party pokemon walk again woops 2025-11-04 18:54:29 +10:00
Carmendar dac2d9e96e Mimikyu animations & ride style changes. - Updated changelog 2025-11-04 01:59:01 -06:00
Landon Wills 5c71680db9 Run scraper 2025-11-04 00:26:13 -05:00
Carmendar 5f5c036f8d Merge branch 'main' into implement_pokemon 2025-11-03 23:14:21 -06:00
Carmendar 1f16c2d542 Updated dewgong anim file. 2025-11-03 23:12:50 -06:00
JazzMcNade 2da9dc50f7 Fixed creative duped beehives creating combees with duplicate UUIDs 2025-11-03 21:30:57 -06:00
Carmendar 092f9ef9f9 Updated Gyarados fly pose. 2025-11-03 20:03:18 -06:00
Landon Wills 2f12b05d43 Run scraper 2025-11-03 19:48:32 -05:00
Guilherme Pereira 42eb08e715 Merge branch 'main' into more-poke-snack-stuff 2025-11-03 18:08:10 -03:00
Guilherme Pereira 03470aa623 add poke snack spawn pokemon pre and post events 2025-11-03 17:58:14 -03:00
Sterrezo 4299aff1bf Added water ride loop sounds and updated the wind loop 2025-11-03 16:57:05 +01:00
Paul fb90ccb86e Fixed dismount not working for non-owner passengers if they have no Pokemon 2025-11-03 22:08:12 +10:00
Paul c112f9615c Merge remote-tracking branch 'origin/main' 2025-11-03 21:42:57 +10:00
Paul fc882190fe /ride no longer works on seatless pokemon, closes #1750 2025-11-03 21:39:48 +10:00
Paul 15d7cd815d Only handle mount transition camera logic for the actual client player. Probably doesn't fix anything? 2025-11-03 21:23:35 +10:00
violet 6b5969fff6 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-03 03:33:13 -05:00
Carmendar 5053c633b7 Grafaiai paint/saliva colors 2025-11-03 02:22:33 -06:00
violet c4294697e6 implemented remodels for scorbunny, raboot, and cinderace 2025-11-03 03:16:37 -05:00
Carmendar dfa1c5e369 Orthworm sand_idle fix 2025-11-03 01:59:46 -06:00
Carmendar 51f3b4357d Implemented Remodels for Steelix and Shroodle line. 2025-11-03 01:59:08 -06:00
Carmendar 220a9741ae Implemented Mime Jr animations. 2025-11-03 01:58:15 -06:00
Carmendar 48a9446f73 Implemented the Vanillite line. 2025-11-03 01:56:52 -06:00
violet f1edfc453e minor adjustments to shuppet's poser 2025-11-03 01:18:40 -05:00
FrankTheFarmer 8d612ec395 Changelog of hatred and anguish 2025-11-03 15:01:03 +10:00
FrankTheFarmer 6d9daf3cf6 Stupid fish's mama 🔴⚪ 2025-11-03 15:00:26 +10:00
FrankTheFarmer c7ecfc74de Stupid fish 🔴🔵⚪ 2025-11-03 14:26:02 +10:00
Hiroku fefdfd877b Merge branch 'let-me-/ride' into 'main'
Fix /ride

Closes #1751

See merge request cable-mc/cobblemon!1927
2025-11-03 02:35:18 +00:00
Landon Wills 35fb170225 Fix /ride 2025-11-02 20:50:39 -05:00
Paul d2e405131f Fixed speculative cast in pokedex FOV multiplier. Closes #1756 2025-11-03 11:37:00 +10:00
Paul b6ec0205ef Fixed NPC gibber sounds playing even when text was skipped. Closes #1755 2025-11-03 11:36:20 +10:00
Paul e57a42e755 Fixed immobile pokemon walking to follow the player. Closes #1757 2025-11-03 11:25:46 +10:00
Carmendar f34a03c8d6 Implemented Carvanha and Sharpedo animations - removed surfacewater swimming from Charizard and Arcanine. 2025-11-02 17:28:22 -06:00
Carmendar 8b1599705f Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-02 13:35:26 -06:00
Carmendar e7f6fc32c4 Implemented Arcanine Animations! 2025-11-02 13:34:39 -06:00
Landon Wills 5119617f00 Check for moonrise and disable conflicting mixin if loaded 2025-11-02 09:39:33 -05:00
Paul 6e84efb53c No Packed Up backpacks either. Your move, Monocle 2025-11-02 22:41:11 +10:00
Paul de3191b768 Some english improvements on new NPC Behaviours 2025-11-02 22:06:27 +10:00
Paul 76ec4b4d5a Merge remote-tracking branch 'origin/main' 2025-11-02 21:34:42 +10:00
Hiroku 25702ade61 Merge branch 'main' into 'main'
dialogue selection interaction and name tag display - done properly this time

See merge request cable-mc/cobblemon!1925
2025-11-02 11:34:19 +00:00
Paul c6da88d0b2 Improvements to GUI pokemon animation config options, pokebait effects, setup some berry gen stuff for vera 2025-11-02 21:32:18 +10:00
violet c4acc09fbd Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-02 03:49:32 -05:00
violet 53b434906b altered various starter pokemon portraits, profiles, and scales 2025-11-02 03:49:22 -05:00
Jolihan b22a31909d Update file en_us.json 2025-11-02 08:09:19 +00:00
Jolihan cbbbacc215 Edit name_tag_display.json 2025-11-02 07:01:40 +00:00
Jolihan566 d22d81209d dialogue selection interaction and name tag display - done properly this time 2025-11-02 16:59:21 +10:00
Carmendar 89b989c46c Updated Changelog 2025-11-02 01:42:05 -05:00
Carmendar 714d51b26e Implemented Tadbulb and Bellibolt animations 2025-11-02 01:35:27 -05:00
Hiroku 8571d78894 Merge branch 'FixGreedyHoneyEaters' into 'main'
Fixed Greedy Honey Eaters

Closes #1725

See merge request cable-mc/cobblemon!1920
2025-11-02 05:54:22 +00:00
JazzMcNade 72c57fde39 Sacc tree spawned beenests are now populated with either Minecraft bees or combees 2025-11-01 21:58:15 -05:00
Carmendar fc5c479f31 two small fixes 2025-11-01 21:48:58 -05:00
Carmendar d3c54924be no more blinky bronzong 2025-11-01 20:57:25 -05:00
Paul 65c5e95ddf Fixed possible crash from bees putting honey in saccarine leaves 2025-11-02 11:56:27 +10:00
Carmendar fc1dec6b4b Shellos & Gastrodon cries implemented 2025-11-01 20:53:45 -05:00
Carmendar 7604af9308 Shellos & Gastrodon cries 2025-11-01 20:48:16 -05:00
Carmendar ab1e138ace Koffing and Weezing animations. 2025-11-01 19:25:38 -05:00
Carmendar 62ee94c71d Bronzong and Camerupt animations - More poser tweaks. 2025-11-01 19:06:26 -05:00
Nadja Reitzenstein 0fae95aabc Reorder smeargle's tail colours to allow handing them cosmetic dyes
Our aspect system has the limitation that you can not easily have two separate systems add mutually exclusive aspects correctly. This means that for cosmetics to work without much duplication, the characteristic rainbow has to set a different aspect with some (but much more limited) duplication in the assignment of textures.
2025-11-01 19:55:55 +01:00
Nadja Reitzenstein bbfd864b33 Clean up Rainbow Aspect provider 2025-11-01 18:43:31 +01:00
Nadja Reitzenstein b107d76762 Cosmetic Item dye affects smeargle tails now 2025-11-01 17:37:04 +01:00
Nadja Reitzenstein 8d4f10349c Use the easier to understand maxBy call 2025-11-01 17:25:23 +01:00
Nadja Reitzenstein f36787e67f Clean up Characteristic calculation
Also ensures characteristics are recalculated on IV updates.
2025-11-01 16:42:59 +01:00
Nadja Reitzenstein fc198c599e Update CHANGELOG.md 2025-11-01 16:23:12 +01:00
Nadja Reitzenstein 26f753880c Implement rotating a feature on lightning hit more sensibly 2025-11-01 16:23:12 +01:00
Nadja Reitzenstein a9ebb0b6f2 Merge thunderHit method for Pokemon entity 2025-11-01 16:23:12 +01:00
Nadja Reitzenstein a7158ee57a Rainbow aspected Smeargle 2025-11-01 16:23:12 +01:00
Nadja Reitzenstein 06c3fd3f09 Make lightning damage only not apply if there was an actual aspect change. 2025-11-01 16:23:12 +01:00
Nadja Reitzenstein 4e196e8a29 Generalise switching aspect behaviour on lightning hit 2025-11-01 16:23:12 +01:00
Nadja Reitzenstein 871f33f442 Make mooshtank switch colour on lightning hit 2025-11-01 16:23:12 +01:00
Polymeta 21c1f912a7 Merge branch 'typo' into 'main'
Update crops.json

See merge request cable-mc/cobblemon!1924
2025-11-01 10:16:37 +00:00
Carmendar a0d9ce12a6 Implemented animations for Mr. Mime and Relicanth - poser/anim tweaks for Dragonite. 2025-11-01 03:59:05 -05:00
Carmendar c07173fc0f Merge branch 'main' into implement_pokemon 2025-11-01 01:54:43 -05:00
violet 3faf8ac302 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-01 01:21:23 -04:00
violet e85b3f3cc5 implemented shuppet and banette 2025-11-01 01:19:52 -04:00
RedGenesectNinja 251a09f78c Implemented Stunfisk and Galarian Stunfisk 2025-10-31 23:43:46 -05:00
dhi_holo 776fb5413f Update crops.json
Apparently missed this file while updating stuff? I swear I didn't but it must not've commited
2025-11-01 14:36:45 +10:00
Paul f645fd9b60 Added support for species-specific move action effects 2025-11-01 11:44:05 +10:00
Landon ac161ae5b4 Merge branch 'orientation-refactor' into 'main'
Refactor orientation to better allow for passengers on rolling rides.

See merge request cable-mc/cobblemon!1910
2025-11-01 01:19:29 +00:00
Jackson Bowes fc3542e3eb Refactor orientation to better allow for passengers on rolling rides. 2025-11-01 01:19:28 +00:00
Gertimoshka 7c44dd204e Remove Old Notifications of Level Up, EXP Gained, and Moves Learned 2025-10-31 15:13:53 +02:00
Hiroku 88932c8c41 Merge branch 'poke-snack-spawner' into 'main'
Makes Poké Snacks act as spawners

See merge request cable-mc/cobblemon!1915
2025-10-31 12:10:36 +00:00
lion 411f98d0ae Makes Poké Snacks act as spawners 2025-10-31 12:10:36 +00:00
Polymeta 02a1929ede Merge branch 'fix-pick-block' into 'main'
Fix picking blocks while riding mounts

Closes #1698

See merge request cable-mc/cobblemon!1922
2025-10-31 12:00:14 +00:00
Jordan ff90059eec Fix picking blocks while riding mounts 2025-10-31 12:00:13 +00:00
Carmendar eca14f61ac Various mount style changes - prep work for Submarine, and removed mountability from 5 pokemon. 2025-10-31 02:35:15 -05:00
Carmendar 9ccf2bb9ad Heracross anims, poser fixes, removed land mount style from select pokemon. 2025-10-31 02:33:30 -05:00
Guilherme Pereira d09d636113 add facing direction to snacks 2025-10-30 16:54:45 -03:00
Guilherme Pereira ff335f779f improve color mixing of snacks 2025-10-30 13:25:37 -03:00
Guilherme Pereira b70316e347 switch the snacks’ colors to be based on food colors again 2025-10-30 10:05:30 -03:00
Kenji_64 eacb0fe587 Forgot the changelog 2025-10-30 13:27:23 +01:00
Kenji_64 1752588cbc New scales for Dreepy and Drakloak 2025-10-30 13:22:48 +01:00
Kenji_64 9e09ac52fc Added animations + ride stats to Dragapult! 2025-10-30 13:22:25 +01:00
Kenji_64 845ade1aeb Added cries to Alolan Vulpix and Ninetales 2025-10-30 11:28:53 +01:00
Carmendar f6bd04f016 Implemented Darmanitan, Gastrodon, Orthworm & Salamence anims - Switched Tentacruel to json poser - fixed minor camera and poser issues. 2025-10-30 02:41:42 -05:00
Landon Wills afa1d9af8b Update riding scraper, scrape pokemon 2025-10-30 03:15:02 -04:00
Landon Wills bf6db8b745 Merge branch 'main' into implement_pokemon 2025-10-30 00:58:03 -04:00
Guilherme Pereira a352e67c1b lots of bugs and rowap berry effect 2025-10-29 21:42:55 -03:00
Guilherme Pereira 71297dfb3a fix nearby check for poke snack 2025-10-29 18:46:08 -03:00
Guilherme Pereira 9141694c2a Merge branch 'main' of gitlab.com:cable-mc/cobblemon into poke-snack-spawner 2025-10-29 18:00:30 -03:00
Gertimoshka 9aef7b9c3b Party Notifications Will Override and Stack if triggered too fast (feeding exp candy as an example) and now pokemon level text will change during animation instead instantly 2025-10-29 16:28:00 +02:00
Carmendar c5bebb1abb Hydreigon geo fix
(I goofed up)
2025-10-29 03:03:12 -05:00
Carmendar 990fed2fe0 The great Camera polishing event of '25. 2025-10-29 02:51:02 -05:00
Polymeta 4a30bb3b04 Merge branch 'seasoning-filters' into 'main'
Cooking Pot Recipes now have filtered

See merge request cable-mc/cobblemon!1919
2025-10-29 07:45:59 +00:00
Carmendar fe77a3cd30 Implemented new Charizard, Staraptor, Dusknoir & Forretress animations, fixed Altaria not using some anims, adjusted floating seat locators.
Also fixed Will O' Wisp particle.
2025-10-29 02:34:02 -05:00
Gertimoshka de9e1949fe Do actually implement all of the animations for party overlay level up 2025-10-29 08:06:14 +02:00
Polymeta fac8c5f510 Merge branch 'party-overlay-config-fix' into 'main'
Party overlay config fix

See merge request cable-mc/cobblemon!1921
2025-10-28 14:41:22 +00:00
lion 2d077c607a Party overlay config fix 2025-10-28 14:41:21 +00:00
Nico Merenq f75e3d11da Translated using Weblate (Russian)
Currently translated at 63.6% (5669 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-10-28 08:50:20 +00:00
Gertimoshka f46968f878 Remove Unnecesary Comments 2025-10-28 07:20:54 +02:00
Nico Merenq 3439aeff1e Translated using Weblate (Russian)
Currently translated at 63.5% (5662 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-10-27 21:50:57 +00:00
Paul 1f8fa8cae3 Prevent snacks from spawning pokemon if no players are nearby 2025-10-27 13:50:33 +10:00
Paul 42e405530c Major rework of Spawner hierarchy, removed SpawnerManagers, moved pokesnacks to be manually ticked 2025-10-27 13:40:52 +10:00
Nico Merenq 2ada7e0b68 Translated using Weblate (Russian)
Currently translated at 63.5% (5659 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-10-26 06:57:00 +00:00
Polymeta b8f73f277d Fix PokeRodFishingBobberEntity baitId detection for ReelInPokemonCriterionCondition
Fixes #1744

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-10-25 21:40:17 +01:00
JazzMcNade 7f6197ab8b Honey slathered logs no longer activated multiple time on the same pokemon, and ignore pokemon that already have their hidden ability. 2025-10-25 14:52:51 -05:00
Polymeta 6df2b996e2 Merge branch 'smarter-scalable-brains' into 'main'
New tools for brain activity management

See merge request cable-mc/cobblemon!1916
2025-10-25 19:39:15 +00:00
Polymeta ddc4bd358d Merge branch 'niche-tags' into 'main'
Berry Tag Updates

See merge request cable-mc/cobblemon!1918
2025-10-25 19:34:59 +00:00
Gertimoshka e197287775 Fixed preview item still using seasoning items even if its invalid by tag 2025-10-25 22:04:47 +03:00
dhi_holo be019c79df Update poke_cake.json
Sadly, Poke Cakes do not get tinted by non-flavour colours, so despite my attempt to allow it, it just doesn't work
2025-10-25 20:45:47 +10:00
dhi_holo 73fe851c58 Merge branch 'seasoning-filters' of https://gitlab.com/cable-mc/cobblemon into seasoning-filters 2025-10-25 20:20:09 +10:00
dhi_holo 8544744530 Tags in Recipes 2025-10-25 20:19:37 +10:00
Gertimoshka 32d7bfcef3 Recipes no longer need to define seasoning tag and will assume it as cobblemon:empty 2025-10-25 12:53:25 +03:00
Gertimoshka 27263cd057 JEI is now filtering seasoning slots additionally based berries 2025-10-25 12:22:08 +03:00
Gertimoshka 55f0962205 Recipes will now not consume seasoning items that are not in seasoning filter of recipe and slots will highlight red if seasoning item does not apply to current recipe 2025-10-25 12:02:22 +03:00
Carmendar 63143832e0 Chinchilla implementation. 2025-10-25 02:53:59 -05:00
Carmendar 29215f5c0c Merge branch 'refs/heads/main' into implement_pokemon 2025-10-25 02:48:22 -05:00
dhi_holo 70bf3e7805 Merge branch 'main' into do-you-get-the-joke 2025-10-25 17:12:40 +10:00
dhi_holo 40c5df46ce Berry Tag Updates
Reformatted how the tag is handled to be a bit cleaner, and allow for more specific berry querying via searching, mod compat, etc
2025-10-25 17:08:06 +10:00
Gertimoshka b4d9d1b963 First working itteration of Popups and EXP Bar animations for level up, new moves and new evos 2025-10-25 09:42:26 +03:00
dhi_holo e753c75c31 Merge branch 'seasoning-filters' of https://gitlab.com/cable-mc/cobblemon into seasoning-filters 2025-10-25 15:52:35 +10:00
dhi_holo 4e96222a4d Tags
Renamed a tag and fixed errors it caused, as well as adding the current 6 Filter tags requested for system upgrades
2025-10-25 15:52:09 +10:00
Paul 4ee90d4cfb Removed unneeded comment 2025-10-25 15:22:29 +10:00
Paul 540cd612c1 Added seasoning tag filter to cooking pot recipes 2025-10-25 14:22:47 +10:00
Guilherme Pereira c76dfc3130 refactor poke snacks to use random ticks 2025-10-25 00:29:06 -03:00
Hiroku 1b1d22fdf3 Merge branch 'social-distancing' into 'main'
Adds random offset to follow herd leader task

See merge request cable-mc/cobblemon!1917
2025-10-25 01:49:48 +00:00
lion 1ee1001774 Adds random offset to follow herd leader task 2025-10-25 01:49:48 +00:00
Paul 533272ef09 u got a loicense for that error? 2025-10-24 20:27:31 +10:00
Carmendar cf5e1bf142 ride stat adjustments and Blastoise anim implementation. 2025-10-24 02:20:43 -05:00
Nico Merenq 4b8196685a Translated using Weblate (Russian)
Currently translated at 63.4% (5653 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-10-24 04:12:32 +00:00
Carmendar d1053468bf Adjusted first person mount view for the paldean tauros variants. 2025-10-23 19:22:54 -05:00
Carmendar f0c41865db Adjusted first person mount view for most mons. 2025-10-23 19:19:36 -05:00
Guilherme Pereira cca9de04a7 avoid poke snack spawners behaving weirdly 2025-10-22 21:39:08 -03:00
Carmendar 2b2264bdca Updated Boat expressions 2: Electric Boogaloo 2025-10-22 19:13:09 -05:00
Guilherme Pereira 78d47004bf remove dead code 2025-10-22 21:12:19 -03:00
Guilherme Pereira 30f97e6243 move poke snack spawner creation to poke snack spawner manager 2025-10-22 21:00:35 -03:00
Neovitalism d117d79d28 Removable Feature Rendering 2025-10-22 18:56:26 -05:00
Carmendar 1e32f7b80a Updated Boat expressions 2025-10-22 17:19:52 -05:00
Guilherme Pereira 3d4d797e7f add bite time effect to poke snacks 2025-10-22 15:08:58 -03:00
Guilherme Pereira 39feb9cf6c hook POI system to poke snacks 2025-10-22 13:53:48 -03:00
Guilherme Pereira 8f53757879 allow poke snacks to override the default pokemon per chunk spawn limit 2025-10-22 10:30:46 -03:00
Guilherme Pereira e1d2f125d6 add bucket multiplying influence to poke snacks 2025-10-22 10:00:59 -03:00
Carmendar cfc8edfa9e Ride stats. 2025-10-22 01:40:12 -05:00
Guilherme Pereira fa3ed69ee2 move poke snack spawner to block entity 2025-10-22 03:38:07 -03:00
Carmendar 417b49beda Hover speed expression increase and updated Metagross Poser. 2025-10-22 01:21:41 -05:00
FrankTheFarmer a2f6a35227 Changelog 2025-10-22 11:11:02 +10:00
FrankTheFarmer b9f1cc5883 Added handmade placeholders for ❤Corphish💖 and 🤷‍♂️Crawdaunt🦞 2025-10-22 11:07:02 +10:00
FrankTheFarmer ad132fe729 Made Corphish and Crawdaunt sink and walk in water 2025-10-22 11:03:29 +10:00
FrankTheFarmer f33892fcd1 Merge branch 'main' into implement_pokemon 2025-10-22 11:01:54 +10:00
Landon 91300e4d03 Merge branch '1.7-spawns' into 'main'
Some JSON tweaks

See merge request cable-mc/cobblemon!1913
2025-10-21 23:38:34 +00:00
Carmendar 2a56709395 Merge branch 'main' into implement_pokemon 2025-10-21 17:57:11 -05:00
Polymeta fc135faf57 revert pokemon number range 2025-10-21 22:48:59 +00:00
Guilherme Pereira 8c02ca3576 create poke snack spawner 2025-10-21 19:45:20 -03:00
Polymeta cdd72c664e fix some typos
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-10-21 23:23:43 +01:00
Polymeta 5f025d0f68 Merge branch 'moomoo-milk' into 'main'
Adds clear stat changes effect to Moomoo Milk

See merge request cable-mc/cobblemon!1911
2025-10-21 21:50:59 +00:00
lion 6af2c807ab Adds clear stat changes effect to Moomoo Milk 2025-10-21 21:50:58 +00:00
Polymeta c45c90c6c7 Merge branch 'main' into 1.7-spawns
# Conflicts:
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0027_sandshrew.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0028_sandslash.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0079_slowpoke.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0080_slowbro.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0194_wooper.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0199_slowking.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0688_binacle.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0689_barbaracle.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0751_dewpider.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0752_araquanid.json
#	common/src/main/resources/data/cobblemon/spawn_pool_world/0845_cramorant.json
#	common/src/main/resources/data/cobblemon/tags/worldgen/biome/is_overworld.json
#	utilityscripts/cobblemon_spawn_csv_to_json.py
2025-10-21 22:38:33 +01:00
Polymeta 1ec97c4c90 Merge branch 'riding-style-molang' into 'main'
Add molang function to get the current riding style of a pokemon

See merge request cable-mc/cobblemon!1912
2025-10-21 06:42:54 +00:00
Landon Wills f0bcd38ac7 Add molang function to get the current riding style of a pokemon 2025-10-21 01:55:19 -04:00
Test f4ba446c79 Merge branch 'restoration-tank-fixes' into 'main'
Small fixes

Closes #1735 and #1741

See merge request cable-mc/cobblemon!1908
2025-10-21 03:49:09 +00:00
Guilherme Pereira 60f98ebfce refactor poke snack 2025-10-21 00:04:20 -03:00
Teggy 08c2a0d07b Translated using Weblate (Spanish)
Currently translated at 85.0% (7578 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-10-20 20:24:26 +00:00
Nico Merenq 1f68fdac8c Translated using Weblate (Russian)
Currently translated at 63.4% (5649 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-10-20 17:26:47 +00:00
Teggy e8d4f0fcf4 Translated using Weblate (Spanish)
Currently translated at 84.7% (7546 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-10-20 17:26:45 +00:00
Guilherme Pereira 36a93bda5a refactor poke snack 2025-10-20 03:10:09 -03:00
阿鱼 5d522bd608 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (8908 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-10-20 05:04:02 +00:00
Paul 8d60b07c54 Merge remote-tracking branch 'origin/main' 2025-10-20 14:45:26 +10:00
Paul 5f9cc86044 Added rouseChance and drowsyChance to RestBehaviour so pokemon don't insta sleep in the wild and may spontaneously wake up 2025-10-20 14:45:06 +10:00
Carmendar 35436c1d09 Dewott no longer sleeps in the void. 2025-10-19 23:26:07 -05:00
Landon a6b7e07cf5 Merge branch 'held-item-fix' into 'main'
Remove pvp check for held item logic

See merge request cable-mc/cobblemon!1907
2025-10-20 03:18:36 +00:00
Landon Wills 0ba6215b8d Elaborate on comment 2025-10-19 23:05:16 -04:00
Guilherme Pereira e2f6fae689 change willDefendSelf combat behaviour default to false 2025-10-19 23:36:52 -03:00
Guilherme Pereira 296aa01d0f remove println 2025-10-19 18:41:38 -03:00
Guilherme Pereira 12ab3f2d07 fix dolphin crash on servers 2025-10-19 18:18:31 -03:00
Guilherme Pereira 5a7a374bc9 Merge branch 'main' of gitlab.com:cable-mc/cobblemon into restoration-tank-fixes 2025-10-19 17:35:50 -03:00
Guilherme Pereira ceece45ad4 make poke snack spawn 4 mons per bite 2025-10-19 17:24:01 -03:00
Landon Wills b344ad66c5 Remove pvp check 2025-10-19 14:44:08 -04:00
Carmendar d66793d186 Merge branch 'main' into implement_pokemon 2025-10-18 16:03:03 -05:00
Carmendar cc00962752 Swadloon do be schmoovin (properly this time) 2025-10-18 15:58:41 -05:00
Paul dbc7af4ad4 Don't need to override the start conditions function for activity aware behavior 2025-10-18 21:40:43 +10:00
Paul 5f5bf01cb5 Added ActivityAwareBehavior and tagging for memories and activities 2025-10-18 21:30:47 +10:00
Polymeta 04f2af22f3 Merge branch 'hide-server-configs' into 'main'
Hide server configs when playing on a server

See merge request cable-mc/cobblemon!1905
2025-10-18 10:06:06 +00:00
lion ea916a0db8 Hide server configs when playing on a server 2025-10-18 10:06:06 +00:00
Guilherme Pereira 3f03afc7eb smooth campfire pot spinning animation 2025-10-18 06:53:20 -03:00
Paul e940483863 Typos corrected 2025-10-18 18:46:37 +10:00
Hiroku 9e3d3df3a9 Merge branch 'patch-1' into 'main'
Added Resource Texture Behaviour.

See merge request cable-mc/cobblemon!1894
2025-10-18 08:42:39 +00:00
Jolihan c18368d777 fixed? 2025-10-18 08:40:24 +00:00
Watuneni iteite 3894a99bc4 Translated using Weblate (Japanese)
Currently translated at 93.5% (8334 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-10-17 18:40:49 +00:00
Hiroku aab5b55204 Merge branch 'Bee-Polite-Bee-Efficient' into 'main'
Pokemon bee behavior rework

See merge request cable-mc/cobblemon!1892
2025-10-17 10:24:14 +00:00
Paul 3e6e346eb9 Nectar aspect shouldn't be mixed case, Jazz!! 2025-10-17 19:39:41 +10:00
Carmendar 3a83ed424f Swadloon do be schmoovin. 2025-10-17 01:46:39 -05:00
Hiroku 7bef6db7b7 Merge branch 'riding-scraper-changes' into 'main'
Add lighting data to riding scraper

See merge request cable-mc/cobblemon!1904
2025-10-17 05:29:07 +00:00
lion 71775328ef Add lighting data to riding scraper 2025-10-17 05:29:07 +00:00
Carmendar cbccc612a4 Spewpa learned how to walk. 2025-10-16 02:07:51 -05:00
Carmendar 63fd5d90c1 Merge branch 'main' into implement_pokemon 2025-10-15 23:42:59 -05:00
Carmendar 92336d6107 Implemented Aerodactyl remodel. 2025-10-15 23:37:00 -05:00
Landon 727785b0b3 Merge branch 'boat-stamina' into 'main'
Adjust stamina logic

See merge request cable-mc/cobblemon!1903
2025-10-16 03:45:39 +00:00
Landon Wills 762241420e Adjust stamina logic 2025-10-15 19:48:10 -04:00
Guilherme Pereira 93011f084b make riding fov effects proportional to minecraft fov effect scale setting 2025-10-15 19:23:51 -03:00
Guilherme Pereira 7c90a8425e fix restoration tank concurrent modification crash #1735 2025-10-15 15:01:41 -03:00
Jolihan 8674cbe788 Update 2 files
- /resource_texture.json
- /common/src/main/resources/data/cobblemon/behaviours/npc/resource_identifier.json
2025-10-15 07:06:20 +00:00
Jolihan 8075fe0bae Update 2 files
- /common/src/main/resources/assets/cobblemon/lang/en_us.json
- /resource_texture.json
2025-10-15 07:03:10 +00:00
Carmendar f3f29ca0ea sky protector remodel. 2025-10-15 02:02:01 -05:00
Polymeta 0152803192 Merge branch 'fix-hide-tooltips' into 'main'
Pulled up the Hide Tooltip check to instead run before any custom tooltip generators are performed.

Closes #1733

See merge request cable-mc/cobblemon!1902
2025-10-15 06:14:22 +00:00
Carmendar 2544cbc252 Cosmetics for Alola-bias Pichu and Pikachu, and cosmetics for Alolan Raichu. 2025-10-14 23:53:32 -05:00
Charzard4261 5e094241e3 Pulled up the Hide Tooltip check to instead run before any custom tooltip generators are performed. 2025-10-14 23:33:08 +01:00
Paul bd028c328d Fixed NPC class variables not being applied to NPCs 2025-10-14 22:43:06 +10:00
Polymeta 598cb1d964 Merge branch 'dead-bushes-bad-omen' into 'main'
Adds bad omen effect to dead bushes

See merge request cable-mc/cobblemon!1901
2025-10-14 08:30:41 +00:00
JazzMcNade 79d264fd94 Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-10-14 00:34:09 -05:00
Guilherme Pereira 5f691d3f1c add bad omen effect to dead bushes 2025-10-13 22:26:29 -03:00
Landon 7be0163e76 Merge branch 'bird-stamina-changes' into 'main'
Bird stamina changes and bird fixes

See merge request cable-mc/cobblemon!1897
2025-10-13 21:51:47 +00:00
Jackson Bowes c0b3068824 Bird stamina changes and bird fixes 2025-10-13 21:51:46 +00:00
阿鱼 9036a2f317 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (8908 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-10-13 12:31:47 +00:00
Polymeta dd35adc05d Merge branch 'help-i-cannot-get-down' into 'main'
Fixed neoforge hover mounts not being able to descend

Closes #1717

See merge request cable-mc/cobblemon!1900
2025-10-13 10:58:40 +00:00
Paul 26b5707317 how about you license deez 2025-10-13 19:37:14 +10:00
Hiroku 75e39f5595 Merge branch 'neoforge-tag-annoyance' into 'main'
Plural Tags Please

See merge request cable-mc/cobblemon!1899
2025-10-13 06:47:59 +00:00
Paul 7fdeaeabef Fixed neoforge hover mounts not being able to descend 2025-10-13 16:45:32 +10:00
阿鱼 c75ab28002 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.3% (8853 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-10-13 06:00:42 +00:00
dhi_holo 809ffd8b90 Merge branch 'main' into neoforge-tag-annoyance 2025-10-13 14:50:58 +10:00
dhi_holo da7610951d Plural Tags Please
NeoForge uses singular form food tags for some reason. Also removed our berries as they're not technically a food and it would break balancing
2025-10-13 14:50:53 +10:00
Nico Merenq 62a8320068 Translated using Weblate (Russian)
Currently translated at 63.2% (5635 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-10-11 20:53:16 +00:00
Watuneni iteite f21b38f66a Translated using Weblate (Japanese)
Currently translated at 93.1% (8300 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-10-11 20:53:15 +00:00
Paul 76fdd1fa98 No more tricky riding pokemon after battles start 2025-10-11 21:04:59 +10:00
阿鱼 596765bb52 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 98.6% (8791 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-10-11 06:00:06 +00:00
Watuneni iteite 297aafba45 Translated using Weblate (Japanese)
Currently translated at 92.9% (8282 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-10-11 06:00:04 +00:00
Polymeta 156983bf58 [skip-ci] changelog 2025-10-10 09:28:59 +00:00
Polymeta c69930b836 Merge branch 'SaferPokeballBreakFree' into 'main'
Avoid suffocation when a pokeball breaks near a wall

See merge request cable-mc/cobblemon!1898
2025-10-10 09:27:56 +00:00
JazzMcNade 6926932340 Merge branch 'main' into SaferPokeballBreakFree 2025-10-10 00:29:18 -05:00
Landon 221b3308fa Merge branch 'fix-boat-crash' into 'main'
Fix typo

See merge request cable-mc/cobblemon!1896
2025-10-09 22:39:05 +00:00
Landon Wills 66840670b6 Fix typo 2025-10-09 17:51:51 -04:00
Hiroku 28887d9116 Merge branch 'do-you-get-the-joke' into 'do-you-get-the-joke'
Eggant Effect Data Pack

See merge request cable-mc/cobblemon!1893
2025-10-08 13:02:28 +00:00
Kyozenno 6ef1bac1d7 Eggant Effect Data Pack 2025-10-08 13:02:27 +00:00
Jolihan 5d6a7807e5 Added Resource Texture Behaviour. This adds a behaviour that allows the user to change the resource identifier of the npc class without needing a new class. 2025-10-08 12:48:20 +00:00
JazzMcNade 20b7eb17f3 simplify 2025-10-07 00:52:36 -05:00
Watuneni iteite a0a682e224 Translated using Weblate (Japanese)
Currently translated at 92.3% (8227 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-10-06 12:15:07 +00:00
JazzMcNade 103ac86345 Merge branch 'main' into SaferPokeballBreakFree 2025-10-05 02:00:56 -05:00
JazzMcNade 8f705a698d Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-10-04 21:16:20 -05:00
JazzMcNade f4fb09947e Change log 2025-10-04 20:51:49 -05:00
JazzMcNade 97e31e341b Licenses! 2025-10-04 19:26:32 -05:00
JazzMcNade 813789235d Serializable hive/flow/leaf memories 2025-10-04 19:10:32 -05:00
Nico Merenq d161b11892 Translated using Weblate (Russian)
Currently translated at 63.1% (5627 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-10-04 22:39:35 +00:00
JazzMcNade 5a82e7e185 Clean up and refactor 2025-10-04 17:15:20 -05:00
JazzMcNade 3bc8d3ce75 Code cleanup 2025-10-04 16:50:23 -05:00
JazzMcNade d9e9fd0f4e Clean up wander and move to hive task 2025-10-04 04:09:11 -05:00
Polymeta fddb203db3 Merge branch 'fix-aprijuice-crash' into 'main'
Aprijuice feeding crash

Closes #1712

See merge request cable-mc/cobblemon!1887
2025-10-03 16:14:39 +00:00
lion 8a8cace5e8 Aprijuice feeding crash 2025-10-03 16:14:38 +00:00
Polymeta 5f5b4ee3c1 Merge branch 'implement_pokemon' into 'main'
Implement pokemon

See merge request cable-mc/cobblemon!1890
2025-10-03 08:19:57 +00:00
JazzMcNade aa6581ae39 WIP hive blacklisting 2025-10-03 02:18:32 -05:00
Paul 8aa9e0191f Shulker Boxes and Traveler's Backpacks cannot be held by Pokémon and make the PC file 5000000gb large anymore 2025-10-03 16:43:35 +10:00
JazzMcNade 8dc09796f8 corrected extra start conditions 2025-10-02 23:57:38 -05:00
JazzMcNade 8f93712edb Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-10-02 23:40:46 -05:00
JazzMcNade b91d1b931e Bees can now give up on a unreachable hive 2025-10-02 23:27:51 -05:00
Test 9d84cbb3ac Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2025-10-02 22:35:54 -04:00
Test 8e730f2b5c fix ride stat exceeding limit 2025-10-02 22:35:24 -04:00
Hiroku 7b5809fd55 Merge branch 'aprijuice-feeding-crash-fix' into 'main'
Aprijuice feeding crash fix

Closes #1712

See merge request cable-mc/cobblemon!1891
2025-10-03 01:22:09 +00:00
PieDuck bc682ddf62 Removes comments 2025-10-03 00:57:04 +01:00
PieDuck 990ead0544 Fixes ConcurrentModificationException crash when feeding pokemon aprijuice 2025-10-03 00:55:38 +01:00
Carmendar 4cf55dc95d Merge branch 'main' into implement_pokemon 2025-10-02 17:54:36 -05:00
Polymeta 27a9f3c704 Merge branch 'ride-settings-network-fixes-electric-boogaloo' into 'main'
Make RideSettingsSyncHandler be correctly sided

See merge request cable-mc/cobblemon!1889
2025-10-02 20:47:01 +00:00
Yasito d70bb243b2 Translated using Weblate (French)
Currently translated at 100.0% (8908 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-10-02 18:49:12 +00:00
Yasito 301a3efb7c Translated using Weblate (French (Canada))
Currently translated at 100.0% (8908 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-10-02 18:49:11 +00:00
Yasito 05b7cbe20a Translated using Weblate (French)
Currently translated at 100.0% (8908 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-10-02 18:38:58 +00:00
Yasito 48cbbc1bef Translated using Weblate (French (Canada))
Currently translated at 100.0% (8908 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-10-02 18:38:57 +00:00
Yasito f8f7c28274 Translated using Weblate (French)
Currently translated at 99.8% (8895 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-10-02 17:13:57 +00:00
Yasito 0ebb53888a Translated using Weblate (French (Canada))
Currently translated at 99.8% (8891 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-10-02 17:13:56 +00:00
Nadja Reitzenstein 83aba7e4a6 Make RideSettingsSyncHandler be correctly sided 2025-10-02 18:57:37 +02:00
Yasito c0071c1525 Translated using Weblate (French)
Currently translated at 99.5% (8868 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-10-02 14:53:46 +00:00
Yasito 71f7b3b3d8 Translated using Weblate (French (Canada))
Currently translated at 99.2% (8841 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-10-02 14:53:45 +00:00
Watuneni iteite bd6d7b7149 Translated using Weblate (Japanese)
Currently translated at 91.1% (8116 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-10-01 00:25:05 +00:00
JazzMcNade 73275626a3 Persist bees that have a valid nectar deposit location 2025-09-30 00:51:29 -05:00
GenotypeXD-Dev 0686428138 Implemented Elgyem, and Beheeyem remodels 2025-09-29 23:47:04 -05:00
GenotypeXD-Dev f05e6008e5 Ho-oh Fixes 2025-09-29 13:33:00 -05:00
Alexis Salgueiro 63de8fe44a Translated using Weblate (French)
Currently translated at 99.5% (8868 of 8908 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-09-29 18:00:45 +00:00
Carmendar 4450164d9c Garchomp can swim in liquid water now. 2025-09-28 23:56:10 -05:00
Carmendar b99899353c Merge branch 'main' into implement_pokemon 2025-09-28 22:39:22 -05:00
violet 608b711833 minor fix to exeggutor's animations 🥚 2025-09-28 00:59:44 -04:00
violet 3adc1b9f30 altered posers for staryu, starmie, and corsola 🫧 2025-09-28 00:35:52 -04:00
violet 478cbc2489 updated models & animations for litwick, lampent, and chandelure 🕯️ 2025-09-27 23:49:26 -04:00
Carmendar 03edb5a385 Merge branch 'main' into implement_pokemon 2025-09-27 02:47:44 -05:00
Carmendar cf77713860 No more Hydreigon quirks while flying. 2025-09-27 01:08:41 -05:00
Carmendar 0494193c9b fixed paldean tauros falling too. 2025-09-26 22:50:30 -05:00
Carmendar 7bee34170d removed non-existant quirk from crobat poser & fixed tauros falling in battle. 2025-09-26 22:47:49 -05:00
JazzMcNade 3a22e387b6 Clean up flower sensor 2025-09-26 00:46:27 -05:00
JazzMcNade 956b3bfcbd removed hive sensor from non-wild bees, clean up 2025-09-26 00:28:43 -05:00
JazzMcNade a9ceddd94a Clean up, disabled hive storage for non-wild bees 2025-09-25 00:50:04 -05:00
JazzMcNade e99c55e812 Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-09-24 01:10:00 -05:00
JazzMcNade 5053d559bc Refactor, tweak start conditions, stop channeled behaviours when exiting the bee activity, allow bees to patrol sacc leaves if no hive is availiable. 2025-09-24 01:09:21 -05:00
Jerzykv 1a30109f1c Galarian Farfetch'd can no longer fly 2025-09-23 15:03:21 +02:00
violet 5088497575 MANECTRIC. 2025-09-21 18:55:04 -04:00
JazzMcNade 31129ef14d Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-09-20 19:44:59 -05:00
Veraxiel 17c71efb17 Added spawns for 1.7 Pokémon. Updated spawns. Updated spawn scraper. 2025-09-08 02:04:58 -04:00
JazzMcNade e80eb91e69 Refactored Combees to only pass through Saccharine Leaves 2025-09-08 01:03:31 -05:00
Veraxiel a5b6a954fd Added "Mansion Dining" preset tag. Updated is_overworld tag. 2025-09-07 20:42:53 -04:00
JazzMcNade 2a295a8796 Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-09-07 03:55:50 -05:00
JazzMcNade 245226f4f6 Refresh/delete hive memory on exiting a hive 2025-09-02 20:31:13 -05:00
JazzMcNade d3e1c2c79d Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-09-02 01:34:58 -05:00
JazzMcNade e04e82c6de Added combee aggression for defending hives, more refactoring 2025-08-27 00:45:12 -05:00
JazzMcNade 95589dd48b Added hasNectar aspect particle effect. Removed programmer textures, removed unused file. 2025-08-23 19:34:02 -05:00
JazzMcNade 4cb17135bd Cancel honey deposit if the leaves are removed 2025-08-23 18:09:53 -05:00
JazzMcNade 8dc23160fc Added hasNectar aspect. Refactored POLLINATED memory to HAS_NECTAR 2025-08-23 17:22:58 -05:00
JazzMcNade 4a96a41c8e Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-08-23 14:40:51 -05:00
JazzMcNade 3f18e7c0bf Combees may pass through leaves to deposit honey in saccharine leaves. 2025-08-19 23:37:24 -05:00
JazzMcNade 3c3a23a397 Merge branch 'LionsFoxesAndWolvesOhMy' into Bee-Polite-Bee-Efficient 2025-08-16 14:38:57 -05:00
JazzMcNade 438de6ed6d Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-08-16 14:36:53 -05:00
dhi_holo 95399a32a8 Tweaks
Fixed the advancements breaking (whoops) and lowered the berry in soil
2025-08-16 18:10:11 +10:00
dhi_holo 7089ff68d4 🍆
That's it, that's the addition

Things that need finishing:
- Bait/Cooking Effects
- Battle Effects (Eggant Berry doesn't exist within our Showdown repo, which it seems to need)
2025-08-16 17:09:02 +10:00
JazzMcNade c754d820a5 Combee no longer gets stuck if it tries to enter a full hive, Will now always attempt to return to a hive in night or rain. 2025-08-15 00:35:38 -05:00
JazzMcNade 81c819ddd3 Pollination more closely reflects vanilla bees. Combee now stay closer to the ground. Combee now correctly update their rotation upon leaving a hive. 2025-08-14 22:26:38 -05:00
JazzMcNade ec3e0bfd04 More beelike hive logic. Nectar is applied more closely to how minecraft bees function 2025-08-11 00:38:42 -05:00
JazzMcNade b61d739e46 Wild Combees can store themselves in beehives, partial rework of hive sensor 2025-08-09 20:34:43 -05:00
JazzMcNade 7a050d5374 Merge branch 'main' into Bee-Polite-Bee-Efficient 2025-08-09 13:58:48 -05:00
JazzMcNade 52076de76a Reduced performance cost of flower sensor 2025-08-09 13:57:43 -05:00
JazzMcNade be8dfd7fa2 Utilize setPositionSafely in breakFree() 2025-07-01 22:04:20 -05:00
3352 changed files with 221234 additions and 45076 deletions

No files matched your search

+2 -1
View File
@@ -12,7 +12,8 @@ out
*.ipr
*.iws
*.iml
.idea
.idea/*
!.idea/icon.png
# gradle
build
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

+9 -1
View File
@@ -12,6 +12,14 @@
- SpawningContext is now SpawnablePosition
- WorldSlice is SpawningZone
- SpawningProspector is now SpawningZoneGenerator
- Majorly refactored the hierarchy of Spawner
- The base Spawner interface provides more functions to allow single-point and area spawning given appropriate inputs.
- TickingSpawner is removed in favour of outside code handling ticking logic.
- AreaSpawner is removed.
- BasicSpawner is the first implementation of Spawner which can be used for any purpose.
- PlayerSpawners are now mixin'd into ServerPlayer and ticked from ServerPlayer#tick.
- A hierarchy diagram can be found at `./docs/spawner-hierarchy.png` in the mod repository.
- The SpawnerManager class has been removed as its functionality is all now handled elsewhere.
- Renamed things in Spawn Rules to go with the other renames:
- contextSelector is now spawnablePositionSelector
- contextSelector is now spawnablePositionSelector
- context is now spawnable_position
+94 -2
View File
@@ -34,10 +34,11 @@
- Added Hyper Training items (IV Modification) as well as some additional candy items to do so (Health Candy, Sickly Candy)
- Added Galarica Nut Bushes
- Many Pokémon (mostly cats) are now feared by phantoms
- Combees are now capable of gathering nectar from flowers and delivering it to either Saccharine leaves or hives. (Hive interactions are restricted to wild Combees)
- Lightning is now affected by a Pokemon's ability/typing
- Pokémon with the ability Lightning Rod draw in lightning similar to a lightning rod block albeit with a lower priority and range, gain immunity to lightning damage, and receive a temporary damage buff.
- Pokémon with the ability Motor Drive are immune to lightning damage and receive a temporary speed buff when struck by lightning
- Pokémon with the ability Volt Absorb are immune to lightning damage and receive Regeneration II for a short duration
- Pokémon with the ability Volt Absorb are immune to lightning damage and receive Instant Health II for a short duration
- Ground type Pokémon are immune to lightning damage
- Added functionality to Everstone when held by a Pokémon; suppresses evolution notification and hides evolve button in summary interface.
- Added optional `filePath` parameter to MoLang functions to allow for global stores (ex. `../global/`). Path must end in a forward slash.
@@ -48,11 +49,18 @@
- Berries can now be smelted into their respective dyes.
- Added Syrupy Apples.
- Added `/runmolang <molang> [<npc>|<player>|<pokemon>]` command that executes a MoLang expression with the provided options as environment variables, as well as the entity (as `q.entity`) that executed the command.
- Added new 69th berry, Eggant.
- Added bubble quirk to Kingler; like Krabby, Kingler will blows bubbles during dusk.
- Added `.Pre` and `.Post` to the following events:
- `PokemonRecallEvent`
- `TradeEvent`
- Added a new gamerule, 'healerHealsPC', when set to true a successful use of a healer will also heal all of the Pokemon in that player's PC.
- Mooshtanks will switch between their red and brown variant when hit by lightning
- Smeargle spawns with differing tail colour depending on its [Characteristic](https://bulbapedia.bulbagarden.net/wiki/Characteristic) stat
- Added smooth level-up animations to the party overlay to replace chat messages.
- Added `min_perfect_ivs` property to PokemonProperties to specify the minimum number of perfect IVs of the Pokemon.
- Added `defaultKeyItems` config option to specify which key items players always have.
- Added `scale_modifier` property to PokemonProperties to modify the scale of the Pokemon.
### Pokémon Added
@@ -84,6 +92,8 @@
- Altaria
- Snorunt
- Glalie
- Shuppet
- Banette
- Latias
- Latios
@@ -132,6 +142,11 @@
- Swadloon
- Leavanny
- Druddigon
- Minccino
- Cinccino
- Vanillite
- Vanillish
- Vanilluxe
#### Gen 6
- Skiddo
@@ -293,6 +308,24 @@
- Tauros - Paldea Blaze
- Tauros - Paldea Combat
- Dewgong
- Exeggutor - Kanto
- Corphish (updated placeholders for crustaceous tripod gait legs)
- Crawdaunt (updated placeholders for crustaceous bipedal legs)
- Dragapult
- Camerupt
- Relicanth
- Heracross
- Salamence
- Staraptor
- Dusknoir
- Arcanine
- Carvanha
- Sharpedo
- Mimikyu
- Dewgong
- Mime Jr
- Gyarados
- Lapras
### Model updates for the following Pokémon
- Cleffa
@@ -320,6 +353,8 @@
- Nosepass
- Probopass
- Kangaskhan
- Scorbunny
- Raboot
- Cinderace
- Magnemite
- Magneton
@@ -403,6 +438,21 @@
- Revavroom
- Nickit
- Thievul
- Litwick
- Lampent
- Chandelure
- Rayquaza
- Aerodactyl
- Basculin
- Basculegion
- Shroodle
- Grafaiai
- Steelix
- Dratini
- Dragonair
- Dragonite
- Cutiefly
- Ribombee
### Changes
- Changed pokemon caught and seen count to update based on the current pokedex being looked
@@ -416,6 +466,8 @@
- Updated some item tags to better integrate behaviours between Cobblemon, Vanilla Minecraft, and other mods
- Removed Cooked Meat, Raw Meat, Protein Ingredients, and Zinc Ingredients, the first two are now using `c` namespace tags, the latter have better integrated use of tags within their recipes which removes need for custom tags.
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
- Updated the `#cobblemon:berries` tag to use subtags located in `data/cobblemon/tags/item/berries`, such as `#cobblemon:berries/hp_recovery` for sorting purposes
- Moved the tag `#cobblemon:mutated_berries` to `#cobblemon:berries/mutation_result`
- Added herbs and snowballs to the consumable in PvE and Wild battle tags
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
- Substantially optimised spawning checks mainly by front-loading biome filtering.
@@ -467,6 +519,10 @@
- Updated `HatchEggEvent.Post` to include the Pokemon that hatched.
- Roseli Berry Trees now naturally generate in their preferred biomes.
- Refactored dynamic lights compat to be more future proof. The dynamic light support is only tested with LambDynamicLights, on NeoForged use that mod in combination with Sinytra Connector
- Shulker Boxes and Traveler's Backpacks AND Packed Up backpacks can no longer be held by Pokémon. Thanks Monocle ;) You could re-enable this with our datapack (but you'd be crazy).
- Moomoo Milk now clears Pokémon stat changes when used in battle.
- Updated Evolution Stone Block light levels
- Added light levels to Evolution Stone Ores. These levels are reduced versions of the full blocks light levels
### Fixes
- Fixed game crashing when removing national pokedex using datapacks
@@ -551,6 +607,11 @@
- Fixed singular Pokémon corruption causing entire storage corruption. Storages will now skip corrupted Pokémon and print an error to console.
- Fixed species additions not being able to properly mark a species as implemented.
- Fixed Pokémon item models not showing a glint when enchanted.
- Fixed some specific bag items not being dropped when used in battle.
- The Corphish line will now sink in water.
- Fixed the "use all berry bait" achievement not being progressed
- Fixed bobber hook and berry sprouts texture sizes causing mipmap issues.
- Fixed head locator not taking into account scale for positioning.
### Developer
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
@@ -588,10 +649,34 @@
- Added a `hoverText` option to PartySelectCallback, to display a tooltip on hovering over a Pokémon in the selection screen.
- `PokemonEntity` instances spawned into the world now appropriately finalize the spawn for mod compatibility.
- Added PokedexManager.obtain as a replacement for .catch which is not a friendly function name in Java.
- Added `Pokemon#hyperTrainIV()` and `IVs#setHyperTrainedIV(Stat, Int)`
- `ElementalType` now implements `ShowdownIdentifiable` to ensure the communcation with showdown stays consistent (also in regards to TeraTypes)
- Pokemon no longer have a change observable
- Pokémon can now have a behaviour changing the value of a species feature on lightning hit:
```JSON
{
"behaviour": {
"lightningHit": {
"rotateFeatures": [
{
"key": "mooshtank",
"chain": ["red", "brown"]
}
]
}
}
}
```
This will change the value of `mooshtank` from `red` to `brown` and vice versa when a lightning strikes this Pokémon. Only chains of which a value is the current value will be considered, so multiple entries for the same key with different chains can be added.
- Removed Npc interface from NPCEntity, the interface is unused and in vanilla is only implemented by VillagerEntity as a means to disable villagers with the `spawn-npcs` server property.
- Added new `Observable#subscribe` methods that take Java Consumers to make usage in Java a little cleaner.
- Annotated a bunch of Kotlin methods and fields for cleaner Java names.
- Added `PartyStore#isEmpty()`.
- Added `ElementalTypes#getRandomType()`.
- Added `IVs#getEffectiveBattleTotal()`.
- Added `IVs.MAX_TOTAL` constant.
- Added `PokemonStats#total()`.
- Add `NatureAdapter` for serializing and deserializing Natures using Gson.
### MoLang & Datapacks
- The following usages for item predicates can now use item conditions like advancements do, you can learn about them in the [Minecraft wiki](https://minecraft.wiki/w/Advancement_definition#minecraft:filled_bucket)
@@ -695,6 +780,12 @@
- Mechanics
- Unlockable Wallpapers
- Starter Data
- Fixed `cobblemon:reel_in_pokemon` criteria not working when used together with a `baitId`
- Also changed the default from `cobblemon:empty_bait` to `any`
- The previous default is still available by using the above as baitId
- Added support for species-specific move action effects, using the format `{move_id}_{species}.json`.
- Added `look_at_entity_types` variable for look_at_entities to specify what entity type or entity tag to look at.
- Added `Looks At Players` behaviour preset that only sets the look target to players.
### Particles
Added new/updated particles for the following moves:
@@ -990,6 +1081,7 @@ Added new/updated particles for the following moves:
- Parametric particle motion now works.
- Event-spawned particles now work.
- Particles can now have independent coordinate spaces.
- Fixed suffocation of Pokémon when a pokeball breaks near a wall
### Developer
- Updated the Pokédex data updated events to always include a `Pokemon` instance, and optionally a `DisguiseData` instance.
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
/**
* Used for mixin shenanigans. ServerPlayers now store their Cobblemon spawner
* inside, so this interface helps execute that.
*
* @author Hiroku
* @since October 27th, 2025
*/
public interface PlayerSpawnerAccessor {
PlayerSpawner getPlayerSpawner();
void setPlayerSpawner(PlayerSpawner spawner);
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.duck;
import com.mongodb.lang.Nullable;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import org.joml.Quaternionf;
import org.joml.Vector3f;
public interface CameraDuck {
BlockGetter cobblemon$getLevel();
@Nullable
Entity cobblemon$getEntity();
Quaternionf cobblemon$getRotation();
Vector3f cobblemon$getForwards();
Vector3f cobblemon$getUp();
Vector3f cobblemon$getLeft();
float cobblemon$getXRot();
void cobblemon$setXRot(float xRot);
float cobblemon$getYRot();
void cobblemon$setYRot(float yRot);
}
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.duck;
import net.minecraft.world.phys.Vec3;
public interface RidePassenger {
void cobblemon$setRideXRot(float rideXRot);
float cobblemon$getRideXRot();
void cobblemon$setRideYRot(float rideYRot);
float cobblemon$getRideYRot();
void cobblemon$setRideEyePos(Vec3 rideEyePos);
Vec3 cobblemon$getRideEyePos();
}
@@ -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.mixin;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(AbstractArrow.class)
public abstract class AbstractArrowMixin {
@Inject(
method = "<init>(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)V",
at = @At("TAIL")
)
private void cobblemon$adjustSpawnPosition(
EntityType<? extends AbstractArrow> entityType,
LivingEntity owner,
Level level,
ItemStack pickupItemStack,
@Nullable ItemStack firedFromWeapon,
CallbackInfo ci
) {
AbstractArrow arrow = (AbstractArrow)(Object)this;
if(!(owner.getVehicle() instanceof OrientationControllable vehicle)) return;
if(!(vehicle instanceof PokemonEntity)) return;
var vehicleController = vehicle.getOrientationController();
// If this is a pokemon ride passenger then use the rider eye position to set the arrow spawn position.
if (owner instanceof RidePassenger ridePassenger && vehicleController != null ) {
var eyePos = ridePassenger.cobblemon$getRideEyePos(); //.add(0.0, -2.0, 0.0);
arrow.setPos(eyePos);
}
}
}
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonMemories;
import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BeehiveBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@Mixin(BeehiveBlockEntity.Occupant.class)
public abstract class BeeOccupantMixin {
@Inject(method = "createEntity", at = @At("RETURN"), cancellable = true)
private void cobblemon$createEntity(Level level, BlockPos pos, CallbackInfoReturnable<Entity> cir) {
// Needing to replicate all the post op stuff on the hive isn't great
if (cir.getReturnValue() == null) {
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
CompoundTag compoundTag = occupant.entityData().copyTag();
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
if (entity instanceof PokemonEntity pokemonEntity) {
var state = level.getBlockState(pos);
var newPos = Vec3.ZERO;
var newYaw = 0f;
var brain = pokemonEntity.getBrain();
if (state.is(BlockTags.BEEHIVES)) {
// position in front of the entrance, face away from the block
var facing = state.getValue(HorizontalDirectionalBlock.FACING);
newPos = pos.relative(facing).getCenter();
newYaw = facing.toYRot();
brain.setMemory(CobblemonMemories.HIVE_LOCATION, pos); // This needs to be set in the case that the hive was picked up and moved.
} else {
// Block has likely been destroyed
var center = pos.getCenter();
newPos = new Vec3(
center.x + level.random.nextFloat() * 0.6 - 0.3,
center.y + level.random.nextFloat() * 0.6 - 0.3,
center.z + level.random.nextFloat() * 0.6 - 0.3
);
newYaw = level.random.nextFloat() * 360F;
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
}
entity.yRotO = newYaw;
entity.setPos(newPos);
// Do honey logic
var hasNectar = brain.getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
if (hasNectar) {
// Remove nectar and reset got to hive cooldown
brain.eraseMemory(CobblemonMemories.HAS_NECTAR);
brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
// Increment honey level of the hive
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
if (i < 5) {
int j = level.random.nextInt(100) == 0 ? 2 : 1;
if (i + j > 5) {
--j;
}
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
}
}
}
cir.setReturnValue(entity);
}
}
}
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
if (entity instanceof PokemonEntity pokemonEntity) {
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "Brain", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
CompoundTag compoundTag = new CompoundTag();
entity.save(compoundTag);
Objects.requireNonNull(compoundTag);
IGNORED_BEE_TAGS.forEach(compoundTag::remove);
Boolean hasNectar = pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
cir.cancel();
}
}
}
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.mixin.accessor.BeeDataAccessor;
import com.cobblemon.mod.common.mixin.accessor.BeehiveBlockEntityAccessor;
import com.cobblemon.mod.common.mixin.accessor.BlockEntityAccessor;
import com.google.common.collect.Lists;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(BeehiveBlockEntity.class)
public abstract class BeehiveBlockEntityMixin {
// Accessor for the private 'stored' field in BeehiveBlockEntity
@Accessor("stored")
public abstract List<BeeDataAccessor> getStored();
@Inject(method = "emptyAllLivingFromHive", at = @At("HEAD"))
private void cobblemon$emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, CallbackInfo ci) {
if (player != null) {
final BeehiveBlockEntity blockEntity = (BeehiveBlockEntity) (Object) this;
// if the block is sedated or the player is too far away, no aggro should be applied
if (blockEntity.isSedated() || player.position().distanceToSqr(blockEntity.getBlockPos().getCenter()) > 16.0)
return;
// from this point need to access private members of the block entity
final BeehiveBlockEntityAccessor blockEntityAccessor = (BeehiveBlockEntityAccessor) this;
List<Object> storedList = blockEntityAccessor.getStored();
List<Entity> list = Lists.newArrayList();
storedList.removeIf((beeData) -> {
BeehiveBlockEntity.Occupant occupant = ((BeeDataAccessor) beeData).invokeToOccupant();
// Checking the for the tag allows us to make sure it's one of our pokemon before trying to rehydrate it into an entity
boolean isPokemon = false;
if (occupant.entityData().contains("id")) {
isPokemon = "cobblemon:pokemon".equals(occupant.entityData().getUnsafe().getString("id"));
}
if (isPokemon) {
return BeehiveBlockEntityAccessor.releaseOccupant(
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
state,
occupant,
list,
releaseStatus,
blockEntityAccessor.savedFlowerPos());
} else {
return false;
}
}
);
for (Entity entity : list) {
if (entity instanceof PokemonEntity) {
((PokemonEntity) entity).getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, player);
}
}
}
}
@Redirect(
method = "releaseOccupant",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"
)
)
private static boolean cobblemon$captureReleasedEntity(
Level level, Entity entity,
Level lvl, BlockPos pos, BlockState state,
BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> bees,
BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos flowerPos) {
if (bees != null && !bees.contains(entity)) {
// Avoid duplicates if vanilla also adds bees to the list on your version
bees.add(entity);
}
return level.addFreshEntity(entity);
}
}
@@ -7,6 +7,7 @@
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.duck.ChannelDuck;
import com.mojang.blaze3d.audio.Channel;
import org.lwjgl.openal.AL10;
@@ -8,18 +8,25 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonNetwork;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry;
import com.cobblemon.mod.common.api.riding.RidingStyle;
import com.cobblemon.mod.common.api.riding.Seat;
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
@@ -32,6 +39,7 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin extends Entity implements OrientationControllable {
@@ -55,6 +63,14 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
}
}
@WrapOperation(method = "baseTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isInWall()Z"))
public boolean cobblemon$preventMountSuffocation(LivingEntity instance, Operation<Boolean> original) {
if (instance.getVehicle() instanceof PokemonEntity) {
return false;
}
return original.call(instance);
}
@Override
public @NotNull HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
Entity vehicle = this.getVehicle();
@@ -116,4 +132,31 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
}
}
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
private void cobblemon$conditionalWaterBreathing(
int currentAir,
CallbackInfoReturnable<Integer> cir
) {
var entity = (LivingEntity) (Object) this;
if (!(entity instanceof Player player)) return;
if (!(player.getVehicle() instanceof PokemonEntity vehicle)) return;
var ridingController = vehicle.getRidingController();
if (ridingController == null) return;
var activeContext = ridingController.getContext();
if (activeContext == null) return;
// If the rider is currently on a submarine and the ride still has stamina.
var stamina = activeContext.getState().getStamina().get();
if (
activeContext.getStyle() == RidingStyle.LIQUID &&
activeContext.getBehaviour().equals(SubmarineBehaviour.Companion.getKEY()) &&
stamina > 0.0f
) {
cir.setReturnValue(currentAir);
cir.cancel();
}
}
}
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.storage.party.PartyStore;
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.duck.PlayerDuck;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
@@ -37,6 +38,7 @@ import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EntityType;
@@ -47,6 +49,7 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import org.objectweb.asm.Opcodes;
@@ -63,7 +66,7 @@ import java.util.*;
import java.util.stream.Collectors;
@Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck {
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
@Unique
private Vector3f cobblemon$driverInput;
@@ -91,6 +94,12 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
@Shadow protected int jumpTriggerTime;
@Unique private final OrientationController cobblemon$orientationController = new OrientationController(this);
@Unique private float cobblemon$rideXRot = 0.0f;
@Unique private float cobblemon$rideYRot = 0.0f;
@Unique private Vec3 cobblemon$rideEyePos = Vec3.ZERO;
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
super(p_20966_, p_20967_);
}
@@ -117,11 +126,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
}
}
@Inject(method = "tick", at = @At("HEAD"))
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
this.cobblemon$orientationController.tick();
}
@Override
public EntityDimensions getDefaultDimensions(Pose pose) {
if (this.getVehicle() instanceof PokemonEntity) {
@@ -307,4 +311,34 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
return cobblemon$lastSentDriverInput;
}
@Override
public float cobblemon$getRideXRot() {
return this.cobblemon$rideXRot;
}
@Override
public void cobblemon$setRideXRot(float rideXRot) {
this.cobblemon$rideXRot = Mth.wrapDegrees(rideXRot);
}
@Override
public float cobblemon$getRideYRot() {
return this.cobblemon$rideYRot;
}
@Override
public void cobblemon$setRideYRot(float rideYRot) {
this.cobblemon$rideYRot = Mth.wrapDegrees(rideYRot);
}
@Override
public Vec3 cobblemon$getRideEyePos() {
return this.cobblemon$rideEyePos;
}
@Override
public void cobblemon$setRideEyePos(Vec3 rideEyePos) {
this.cobblemon$rideEyePos = rideEyePos;
}
}
@@ -15,8 +15,10 @@ 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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Arrays;
import java.util.Map;
@Mixin(RecipeBookSettings.class)
@@ -30,4 +32,14 @@ public class RecipeBookSettingsMixin {
states.put(RecipeBookType.valueOf("COOKING_POT"), new RecipeBookSettings.TypeSettings(true, true));
}
@Redirect( method = "read(Lnet/minecraft/network/FriendlyByteBuf;)Lnet/minecraft/stats/RecipeBookSettings;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/RecipeBookType;values()[Lnet/minecraft/world/inventory/RecipeBookType;"))
private static RecipeBookType[] cobblemon$valuesReadRedirect() {
return Arrays.stream(RecipeBookType.values()).filter( recipeBookType -> !RecipeBookType.valueOf("COOKING_POT").equals(recipeBookType) ).toArray(RecipeBookType[]::new);
}
@Redirect( method = "write(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/RecipeBookType;values()[Lnet/minecraft/world/inventory/RecipeBookType;"))
private RecipeBookType[] cobblemon$valuesWriteRedirect() {
return Arrays.stream(RecipeBookType.values()).filter( recipeBookType -> !RecipeBookType.valueOf("COOKING_POT").equals(recipeBookType) ).toArray(RecipeBookType[]::new);
}
}
@@ -8,33 +8,70 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.PlayerSpawnerAccessor;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ServerPlayer.class)
public abstract class ServerPlayerMixin {
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
@Shadow
public abstract ServerLevel serverLevel();
@Unique
public PlayerSpawner cobblemon$spawner;
@Override
public PlayerSpawner getPlayerSpawner() {
ServerPlayer player = (ServerPlayer)(Object)this;
if (cobblemon$spawner == null) {
cobblemon$spawner = PlayerSpawnerFactory.INSTANCE.create(player);
}
return cobblemon$spawner;
}
@Override
public void setPlayerSpawner(PlayerSpawner spawner) {
this.cobblemon$spawner = spawner;
}
@Inject(method = "tick", at = @At("TAIL"))
private void cobblemon$tickSpawner(CallbackInfo ci) {
if (!Cobblemon.config.getEnableSpawning()) {
return;
} else if (!serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
return;
}
getPlayerSpawner().tick();
}
@Inject(method = "rideTick", at = @At("HEAD"))
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
if (!(this instanceof OrientationControllable controllable)) return;
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((ServerPlayer)(Object)this);
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
ServerPlayer player = (ServerPlayer)(Object)this;
Entity vehicle = player.getVehicle();
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation(vehicle);
controllableVehicle.getOrientationController().setActive(shouldUseCustomOrientation);
}
@Unique
private boolean cobblemon$shouldUseCustomOrientation(ServerPlayer player) {
var playerVehicle = player.getVehicle();
if (playerVehicle == null) return false;
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
private boolean cobblemon$shouldUseCustomOrientation(Entity entity) {
if (entity == null) return false;
if (!(entity instanceof PokemonEntity pokemonEntity)) return false;
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
return behaviour.shouldRoll(settings, state, pokemonEntity);
});
@@ -42,8 +79,9 @@ public abstract class ServerPlayerMixin {
@Inject(method = "stopRiding", at = @At("HEAD"))
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
if (!(this instanceof OrientationControllable controllable)) return;
controllable.getOrientationController().setActive(false);
ServerPlayer player = (ServerPlayer)(Object)this;
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
controllableVehicle.getOrientationController().setActive(false);
}
//TODO: Switch to sending out on load instead of preventing saving
@@ -51,5 +89,4 @@ public abstract class ServerPlayerMixin {
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
return original && !(entity instanceof PokemonEntity);
}
}
@@ -55,86 +55,6 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
@Shadow
public abstract boolean isActive(SoundInstance sound);
@Inject(method = "play",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/sounds/ChannelAccess$ChannelHandle;execute(Ljava/util/function/Consumer;)V"
),
cancellable = true
)
private void cobblemon$overrideChannelExecute(
SoundInstance sound,
CallbackInfo ci,
@Local(name = "h") float h,
@Local(name = "i") float i,
@Local(name = "g") float g,
@Local(name = "bl2") boolean bl2,
@Local(name = "bl3") boolean bl3,
@Local(name = "bl") boolean bl,
@Local(name = "vec3") Vec3 vec3,
@Local(name = "channelHandle") ChannelAccess.ChannelHandle handle
) {
if (!(sound instanceof RideLoopSound rideSound)) return;
if (handle == null) return;
handle.execute((channel) -> {
channel.setPitch(i);
channel.setVolume(h);
if (rideSound.getRideAttenuation() == RideAttenuationModel.LINEAR) {
channel.linearAttenuation(g);
} else if (rideSound.getRideAttenuation() == RideAttenuationModel.EXPONENTIAL){
((ChannelDuck) channel).cobblemon$inverseAttenuation(g);
} else {
channel.disableAttenuation();
}
// Apply low pass filter if the rideSound dictate that it should be muffled
if (rideSound.getShouldMuffle()) {
((ChannelDuck) channel).cobblemon$applyLowPassFilter(1.0f, rideSound.getMuffleAmount());
} else {
((ChannelDuck) channel).cobblemon$clearFilters();
}
channel.setLooping(bl2 && !bl3);
channel.setSelfPosition(vec3);
channel.setRelative(bl);
});
}
@Inject(
method = "tickNonPaused",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/sounds/ChannelAccess$ChannelHandle;execute(Ljava/util/function/Consumer;)V",
ordinal = 0
)
)
private void cobblemon$tickableSoundTick(
CallbackInfo ci,
@Local(name = "tickableSoundInstance") TickableSoundInstance instance,
@Local(name = "channelHandle", ordinal = 0) ChannelAccess.ChannelHandle handle,
@Local(name = "f", ordinal = 0) float volume,
@Local(name = "g", ordinal = 0) float pitch,
@Local(name = "vec3", ordinal = 0) Vec3 vec3
) {
if (!(instance instanceof RideLoopSound rideSound)) return;
handle.execute(channel -> {
channel.setVolume(volume);
channel.setPitch(pitch);
channel.setSelfPosition(vec3);
// Apply low pass filter if the rideSound dictate that it should be muffled
if (rideSound.getShouldMuffle()) {
((ChannelDuck) channel).cobblemon$applyLowPassFilter(1.0f, rideSound.getMuffleAmount());
} else {
((ChannelDuck) channel).cobblemon$clearFilters();
}
});
}
/** Resumes the Source belonging to the queried SoundInstance. */
private void resume(SoundInstance sound) {
ChannelAccess.ChannelHandle sourceManager = this.instanceToChannel.get(sound);
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(targets = "net.minecraft.world.level.block.entity.BeehiveBlockEntity$BeeData")
public interface BeeDataAccessor {
@Invoker("toOccupant")
BeehiveBlockEntity.Occupant invokeToOccupant();
}
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.gen.Invoker;
import java.util.List;
@Mixin(BeehiveBlockEntity.class)
public interface BeehiveBlockEntityAccessor {
@Accessor("stored")
List<Object> getStored();
@Accessor("savedFlowerPos")
BlockPos savedFlowerPos();
/**
* Access the private static method:
* private static void releaseOccupant(Level level, BlockPos pos, BeeData beeData, ...)
*/
@Invoker("releaseOccupant")
static boolean releaseOccupant(Level level, BlockPos pos, BlockState state, BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> storedInHives, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos storedFlowerPos) {
throw new AssertionError(); // Mixin will overwrite
}
}
@@ -8,13 +8,14 @@
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.Camera;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Camera.class)
public interface CameraAccessor {
@Accessor("level")
BlockGetter getLevel();
}
@Mixin(BlockEntity.class)
public interface BlockEntityAccessor {
@Accessor("level") Level getLevel();
@Accessor("worldPosition") BlockPos getWorldPosition();
}
@@ -27,7 +27,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(BrewingStandMenu.class)
public abstract class BrewingStandMenuMixin {
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/inventory/ContainerData;)V", at = @At("TAIL"))
private void captureLevel(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData, CallbackInfo ci) {
var recipeManager = playerInventory.player.level().getRecipeManager();
@@ -37,9 +36,4 @@ public abstract class BrewingStandMenuMixin {
}
}
}
@WrapOperation(method = "quickMoveStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/BrewingStandMenu$PotionSlot;mayPlaceItem(Lnet/minecraft/world/item/ItemStack;)Z"))
private boolean cobblemon$isPotionBottle(ItemStack stack, Operation<Boolean> original, @Local(argsOnly = true) Player player) {
return BrewingStandRecipe.Companion.isBottle(stack, player.level().getRecipeManager()) || original.call(stack);
}
}
@@ -34,7 +34,8 @@ public class AbstractClientPlayerMixin {
} else {
// Only modify fov through riding if the pokedex is not open
LocalPlayer player = (LocalPlayer) (Object) this;
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
// Only modify fov for the driver and not the passengers
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
PokemonEntity ride = (PokemonEntity) player.getVehicle();
// Return custom fov mult for riding
@@ -8,87 +8,61 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.riding.Rideable;
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.duck.CameraDuck;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix3f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Camera.class)
public abstract class CameraMixin {
@Shadow private Entity entity;
@Shadow @Final private Quaternionf rotation;
@Shadow @Final private Vector3f forwards;
@Shadow @Final private Vector3f up;
@Shadow @Final private Vector3f left;
@Shadow private float xRot;
@Shadow private float yRot;
public abstract class CameraMixin implements CameraDuck {
@Shadow private float eyeHeight;
@Shadow private float eyeHeightOld;
@Shadow private BlockGetter level;
@Shadow private Entity entity;
@Final @Shadow private Quaternionf rotation;
@Final @Shadow private Vector3f forwards;
@Final @Shadow private Vector3f up;
@Final @Shadow private Vector3f left;
@Shadow private float yRot;
@Shadow private float xRot;
@Shadow protected abstract void setPosition(Vec3 pos);
@Unique private float returnTimer = 0;
@Unique private float rollAngleStart = 0;
@Unique Minecraft minecraft = Minecraft.getInstance();
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
if (!(this.entity instanceof OrientationControllable controllable)) return;
var controller = controllable.getOrientationController();
if (!controller.isActive() && controller.getOrientation() != null) {
if(this.returnTimer < 1) {
//Rotation is taken from entity since we no longer handle mouse ourselves
//Stops a period of time when you can't input anything.
controller.getOrientation().set(
new Matrix3f()
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
);
if(rollAngleStart == 0){
this.returnTimer = 1;
controller.reset();
return;
}
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
cobblemon$applyRotation();
this.returnTimer += .05F;
ci.cancel();
} else {
this.returnTimer = 1;
controller.reset();
}
return;
}
if (controller.getOrientation() == null) return;
cobblemon$applyRotation();
this.returnTimer = 0;
this.rollAngleStart = controller.getRoll();
ci.cancel();
@Override public BlockGetter cobblemon$getLevel() {
return level;
}
@Override public Entity cobblemon$getEntity() {
return entity;
}
@Override public Quaternionf cobblemon$getRotation() { return rotation; }
@Override public Vector3f cobblemon$getForwards() { return forwards; }
@Override public Vector3f cobblemon$getUp() { return up; }
@Override public Vector3f cobblemon$getLeft() { return left; }
@Override public float cobblemon$getXRot() { return xRot; }
@Override public void cobblemon$setXRot(float xRot) { this.xRot = xRot; }
@Override public float cobblemon$getYRot() { return yRot; }
@Override public void cobblemon$setYRot(float yRot) { this.yRot = yRot; }
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
public void cobblemon$positionCamera(Camera instance, double x, double y, double z, Operation<Void> original, @Local(ordinal = 1, argsOnly = true) boolean thirdPersonReverse) {
Entity entity = instance.getEntity();
@@ -97,49 +71,22 @@ public abstract class CameraMixin {
if(vehicle instanceof Rideable){
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(
instance,
entity,
vehicle,
x,
y,
z,
thirdPersonReverse,
eyeHeightOld,
eyeHeight
instance,
entity,
vehicle,
thirdPersonReverse,
eyeHeight,
eyeHeightOld
);
if(position != null){
if(position != null) {
setPosition(position);
return;
}
}
// reset the rotation values if it is now not being ridden.
MountedCameraRenderer.INSTANCE.setSmoothRotation(null);
original.call(instance, x, y, z);
}
@Unique
private void cobblemon$applyRotation(){
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
var controller = controllable.getOrientationController();
var newRotation = controller.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
if (this.minecraft.options.getCameraType().isMirrored()) {
newRotation.rotateY((float)Math.toRadians(180));
}
this.rotation.set(newRotation);
this.xRot = controller.getPitch();
this.yRot = controller.getYaw();
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
}
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
public void stopMoveIfRolling(Camera instance, float zoom, float dy, float dx, Operation<Void> original) {
Entity entity = instance.getEntity();
Entity vehicle = entity.getVehicle();
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getThirdPersonViewBobbing()) {
original.call(instance, zoom, dy, dx);
}
}
}
@@ -9,15 +9,21 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.function.Predicate;
@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Unique
@@ -42,4 +48,16 @@ public class GameRendererMixin {
lastTime = newTime;
}
@ModifyArg(
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;"
),
index = 4
)
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local(ordinal = 0, argsOnly = true) Entity entity) {
return (entityX) -> !(entity.getVehicle() == entityX && entityX instanceof PokemonEntity) && original.test(entityX);
}
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.geom.ModelPart;
@@ -68,6 +69,17 @@ public class HumanoidModelMixin {
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
);
// If the player is on a rollable ride then use the ride local rotations to rotate the head
// This is to allow the player head to face the correct direction when "freelooking"
if (entity instanceof RidePassenger playerRotater &&
vehicle instanceof OrientationControllable controller &&
controller.getOrientationController().isActive()) {
this.head.xRot = playerRotater.cobblemon$getRideXRot();
headPitch = playerRotater.cobblemon$getRideXRot();
this.head.yRot = playerRotater.cobblemon$getRideYRot();
netHeadYaw = playerRotater.cobblemon$getRideYRot();
}
if (!shouldRotatePlayerHead) {
netHeadYaw = 0f;
headPitch = 0f;
@@ -36,9 +36,9 @@ public class ItemInHandRendererMixin {
}
}
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 1))
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V"))
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
if (!(Minecraft.getInstance().player instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
if (!(Minecraft.getInstance().player != null && Minecraft.getInstance().player.getVehicle() instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
instance.mulPose(quaternion);
}
}
@@ -19,9 +19,11 @@ import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
import com.cobblemon.mod.common.duck.PlayerDuck;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket;
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.CameraType;
import net.minecraft.client.Minecraft;
@@ -29,12 +31,10 @@ import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.player.Input;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
@@ -55,6 +55,10 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
@Unique Matrix3f cobblemon$lastOrientation;
@Unique float cobblemon$lastRideXRot;
@Unique float cobblemon$lastRideYRot;
@Unique Vec3 cobblemon$lastRideEyePos;
@Unique boolean cobblemon$isDoubleJumping = false;
@Shadow
@@ -72,30 +76,35 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
super(clientLevel, gameProfile);
}
// @Inject(method = "sendPosition", at = @At("TAIL"))
// private void cobblemon$updateRotationMatrix(CallbackInfo ci) {
// if (!(this instanceof OrientationControllable controllable)) return;
// var controller = controllable.getOrientationController();
// if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
// cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
// CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
// }
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
private void cobblemon$updateRotationMatrixPassenger(CallbackInfo ci) {
if (!(this instanceof OrientationControllable controllable)) return;
var controller = controllable.getOrientationController();
if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
var vehicleController = controllableVehicle.getOrientationController();
if (!vehicleController.isActive() || vehicleController.getOrientation() == cobblemon$lastOrientation) return;
cobblemon$lastOrientation = vehicleController.getOrientation() != null ? new Matrix3f(vehicleController.getOrientation()) : null;
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(this.getVehicle().getId(), vehicleController.getOrientation()));
}
@Inject(method = "rideTick", at = @At("HEAD"))
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
if (Minecraft.getInstance().player != (Object)this) return;
if (!(this instanceof OrientationControllable controllable)) return;
var driver = (LocalPlayer)(Object)this;
var vehicle = driver.getVehicle();
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
var vehicleController = controllableVehicle.getOrientationController();
// If the player has just switched to riding a custom orientation ride then set their
// x and y rots local to the vehicle rots(if the controller wasn't active and will now be active)
// This ensures that on transition your camera stays in the same spot
if (!vehicleController.isActive() && shouldUseCustomOrientation) {
// Set local to the vehicle x and yrot so
var playerRotater = (RidePassenger)driver;
playerRotater.cobblemon$setRideXRot(Mth.wrapDegrees(driver.getXRot() - vehicle.getXRot()));
playerRotater.cobblemon$setRideYRot(Mth.wrapDegrees(driver.getYRot() - vehicle.getYRot()));
}
vehicleController.setActive(shouldUseCustomOrientation);
}
@Inject(method = "rideTick", at = @At("HEAD"))
@@ -115,6 +124,36 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(driverInput));
}
@Inject(method = "rideTick", at = @At("HEAD"))
private void cobblemon$updateRiderRotationsRideTick(CallbackInfo ci) {
if (Minecraft.getInstance().player != (Object)this) return;
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
var passenger = (LocalPlayer)(Object)this;
var playerRotater = (RidePassenger)passenger;
// Gather Rider Rotation info
var rideXRot = playerRotater.cobblemon$getRideXRot();
var rideYRot = playerRotater.cobblemon$getRideYRot();
var rideEyePos = playerRotater.cobblemon$getRideEyePos();
// Check for a change in the values before sending them.
if (cobblemon$lastRideXRot != rideXRot ||
cobblemon$lastRideYRot != rideYRot ||
cobblemon$lastRideEyePos != rideEyePos
) {
// Update 'last' values
cobblemon$lastRideXRot = rideXRot;
cobblemon$lastRideYRot = rideYRot;
cobblemon$lastRideEyePos = rideEyePos;
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos));
}
}
@Unique
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
var playerVehicle = player.getVehicle();
@@ -129,8 +168,8 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
public void stopRiding() {
super.stopRiding();
if (Minecraft.getInstance().player != (Object)this) return;
if (!(this instanceof OrientationControllable controllable)) return;
controllable.getOrientationController().setActive(false);
if (!(this instanceof OrientationControllable controllableVehicle)) return;
controllableVehicle.getOrientationController().setActive(false);
}
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
@@ -161,7 +200,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
this.cobblemon$survivalJumpTriggerTime = 0;
}
else {
this.cobblemon$survivalJumpTriggerTime = 7;
this.cobblemon$survivalJumpTriggerTime = 12;
}
}
else if (this.cobblemon$survivalJumpTriggerTime > 0) {
@@ -188,33 +227,17 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
Entity vehicle = this.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity) {
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
String locatorName = delegate.getSeatLocator(this);
MatrixWrapper locator = delegate.getLocatorStates().get(locatorName);
if (locator == null) {
return super.pick(hitDistance, partialTicks, hitFluids);
}
// Get player object
var passenger = (LocalPlayer)(Object)this;
var playerRotater = (RidePassenger)passenger;
Vec3 locatorOffset = locator != null ? new Vec3(locator.getMatrix().getTranslation(new Vector3f())) : Vec3.ZERO;
OrientationController controller = this.getOrientationController();
float currEyeHeight = this.getEyeHeight();
Vector3f offset = new Vector3f(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f));
if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) {
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemonEntity.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
offset.add(cobblemon$getFirstPersonOffset(model, locatorName));
}
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(offset));
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
// Gather eye position from stored 1st person camera position calculation
var eyePosition = playerRotater.cobblemon$getRideEyePos();
Vec3 viewVector = this.getViewVector(partialTicks);
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
return this.level()
.clip(
new ClipContext(
@@ -10,13 +10,16 @@ package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.Blaze3D;
import kotlin.Pair;
import net.minecraft.client.Minecraft;
import net.minecraft.client.MouseHandler;
import net.minecraft.client.player.LocalPlayer;
@@ -32,6 +35,9 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import static com.google.common.primitives.Floats.min;
import static net.minecraft.util.Mth.lerp;
@Mixin(MouseHandler.class)
public abstract class MouseHandlerMixin {
@Shadow private double accumulatedScrollY;
@@ -117,8 +123,6 @@ public abstract class MouseHandlerMixin {
@Local(argsOnly = true) double d,
@Local(argsOnly = true) double movementTime
) {
boolean returnValue = true;
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
if (usageContext.getScanningGuiOpen()) {
this.smoothTurnY.reset();
@@ -126,34 +130,78 @@ public abstract class MouseHandlerMixin {
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6 + 0.2;
var spyglassSensitivity = Math.pow(defaultSensitivity, 3);
var lookSensitivity = spyglassSensitivity * 8.0;
var sensitivity = Mth.lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
var sensitivity = lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
var yRotationFlip = this.minecraft.options.invertYMouse().get() ? -1 : 1;
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity * yRotationFlip));
returnValue = false;
}
var vehicle = player.getVehicle();
if (!(vehicle instanceof PokemonEntity)) return true;
// Clamp player rotation if riding and the vehicle demands it
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity vehicle) {
vehicle.clampPassengerRotation(player);
if (player.isPassenger() && vehicle instanceof PokemonEntity pokeVehicle) {
pokeVehicle.clampPassengerRotation(player);
}
if (!(player instanceof OrientationControllable controllable)) return true;
if (!controllable.getOrientationController().isActive()) {
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
xMouseSmoother.reset();
yMouseSmoother.reset();
pitchSmoother.reset();
rollSmoother.reset();
yawSmoother.reset();
return returnValue;
return true;
}
// Send mouse input to be interpreted into rotation
// deltas by the ride controller
var vehicleController = controllableVehicle.getOrientationController();
var lookaroundButtonPressed = Minecraft.getInstance().mouseHandler.isMiddlePressed();
Pair<Boolean, Boolean> mouseShouldModifyDriver = ((PokemonEntity) vehicle).ifRidingAvailableSupply(new Pair(false, false), (behaviour, settings, state) -> {
return behaviour.mouseModifiesDriverRotation(
settings,
state,
(PokemonEntity) vehicle
);
});
//-------------------------------------------------------------------------
// If looking around then modify the players orientation instead and zero the mouse deltas so the mouse doesn't
// affect the vehicle orientation when looking around.
// If the client is a passenger it will modify these rotations and return
//-------------------------------------------------------------------------
if (lookaroundButtonPressed || player.getControlledVehicle() == null) {
// Modify driver rotations
cobblemon$setDriverRotations(player, cursorDeltaX, cursorDeltaY);
// If the player/passenger is not the driver then return and ignore all vehicle rotation logic
if (player.getControlledVehicle() == null) return false;
// Set to zero so that vehicle rotations don't also get affected by movement.
cursorDeltaX = 0.0;
cursorDeltaY = 0.0;
} else if (mouseShouldModifyDriver.getFirst()) { // If not freelooking then check modification per mouse input dimension
cobblemon$setDriverRotations(player, cursorDeltaX, 0.0);
cursorDeltaX = 0.0;
} else if (mouseShouldModifyDriver.getSecond()) {
cobblemon$setDriverRotations(player, 0.0, cursorDeltaY);
cursorDeltaY = 0.0;
}
//-------------------------------------------------------------------------
// Smoothly return driver rotations to zero when needed
//-------------------------------------------------------------------------
var playerRotater = (RidePassenger)player;
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getFirst()){
playerRotater.cobblemon$setRideYRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideYRot()), 0.0f));
}
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getSecond()) {
playerRotater.cobblemon$setRideXRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideXRot()), 0.0f));
}
// Send mouse input to be interpreted into rotation deltas by the ride controller
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
// Perform Rotation using mouse influenced rotation deltas.
controllable.getOrientationController().rotate(
vehicleController.rotate(
(float) angVecMouse.x,
(float) angVecMouse.y,
(float) angVecMouse.z
@@ -163,17 +211,16 @@ public abstract class MouseHandlerMixin {
var angRot = cobblemon$getAngularVelocity(movementTime);
// Apply smoothing if requested by the controller.
// This Might be best if done by the controller itself?
if(cobblemon$shouldUseAngVelSmoothing()) {
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
controllable.getOrientationController().rotate((float) yaw, (float) pitch, (float) roll);
vehicleController.rotate((float) yaw, (float) pitch, (float) roll);
}
// Otherwise simply apply the smoothing
else {
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
vehicleController.rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
}
return false;
}
@@ -186,10 +233,11 @@ public abstract class MouseHandlerMixin {
@Inject(method = "handleAccumulatedMovement", at = @At("TAIL"))
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci) {
if (minecraft.player == null) return;
if (!(minecraft.player instanceof OrientationControllable controllable)) return;
if (!controllable.getOrientationController().isActive()) return;
if (!(minecraft.player.getVehicle() instanceof OrientationControllable vehicleControllable)) return;
if (!(vehicleControllable.getOrientationController() instanceof OrientationController vehicleController)) return;
if (vehicleController.getOrientation() == null) return;
if (minecraft.isPaused()) return;
if (isMouseGrabbed()) return;
if (this.isMouseGrabbed()) return; // return if turnPlayer() has already run this pass
this.turnPlayer(cobblemon$timeDelta);
}
@@ -251,6 +299,21 @@ public abstract class MouseHandlerMixin {
return Math.pow(sensitivity, 3);
}
@Unique
private void cobblemon$setDriverRotations(LocalPlayer player, double cursorDeltaX, double cursorDeltaY) {
// the vanilla turn() method redone so that it uses rideRotations.
float f = (float)cursorDeltaY * 0.15F; // Note: turn() uses xRot for pitch (up/down)
float g = (float)cursorDeltaX * 0.15F; // Note: turn() uses yRot for yaw (left/right)
var playerRotater = (RidePassenger)player;
playerRotater.cobblemon$setRideXRot(playerRotater.cobblemon$getRideXRot() + f);
playerRotater.cobblemon$setRideYRot(playerRotater.cobblemon$getRideYRot() + g);
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -90.0F, 90.0F));
playerRotater.cobblemon$setRideYRot(Mth.clamp(playerRotater.cobblemon$getRideYRot(), -105.0F, 105.0F));
if (player.getVehicle() != null) {
player.getVehicle().onPassengerTurned(player);
}
}
@Unique
private boolean cobblemon$shouldUseAngVelSmoothing() {
var player = minecraft.player;
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import net.minecraft.client.CameraType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Options.class)
public abstract class OptionsMixin {
/**
* Only allow third person on rollables when motion sick cam is enabled
*/
@Inject(
method = "getCameraType",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$forceThirdPerson(CallbackInfoReturnable<CameraType> cir) {
var mc = Minecraft.getInstance();
if(!(mc.player instanceof Player player)) return;
if(!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
if(vehicle.getOrientationController() == null) return;
// Force third person if on an active rollable vehicle and roll is disabled.
if (Cobblemon.config.getDisableRoll() && vehicle.getOrientationController().isActive()) {
cir.setReturnValue(CameraType.THIRD_PERSON_BACK);
cir.cancel();
}
}
}
@@ -8,20 +8,25 @@
package com.cobblemon.mod.common.mixin.entity;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Entity.class)
public abstract class EntityMixin {
@@ -57,5 +62,43 @@ public abstract class EntityMixin {
return original.call(entity);
}
@Inject(
method = "getEyePosition(F)Lnet/minecraft/world/phys/Vec3;",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$modifyEyePosition_partial(float partialTicks, CallbackInfoReturnable<Vec3> cir) {
var entity = (Entity)(Object)this;
if (entity.level().isClientSide) return;
if (!(entity instanceof Player player)) return;
if (!(player instanceof RidePassenger ridePassenger)) return;
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
var vehicleController = vehicle.getOrientationController();
if (vehicleController == null) return;
// TODO: Determine if it needs partialtick involved.
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
cir.setReturnValue(customEyePos);
}
@Inject(
method = "getEyePosition()Lnet/minecraft/world/phys/Vec3;",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$modifyEyePosition_noPartial(CallbackInfoReturnable<Vec3> cir) {
var entity = (Entity)(Object)this;
if (entity.level().isClientSide) return;
if (!(entity instanceof Player player)) return;
if (!(player instanceof RidePassenger ridePassenger)) return;
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
var vehicleController = vehicle.getOrientationController();
if (vehicleController == null) return;
// TODO: Determine if it needs partialtick involved.
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
cir.setReturnValue(customEyePos);
}
}
@@ -83,6 +83,7 @@ import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacke
import com.cobblemon.mod.common.permission.LaxPermissionValidator
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
@@ -293,6 +294,7 @@ object Cobblemon {
SHINY_ASPECT.register()
GENDER_ASPECT.register()
COSMETIC_SLOT_ASPECT.register()
CHARACTERISTIC_RAINBOW_ASPECT.register()
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
@@ -11,16 +11,26 @@ package com.cobblemon.mod.common
import net.minecraft.world.entity.schedule.Activity
object CobblemonActivities {
@JvmField
val activities = mutableListOf<Activity>()
@JvmField
val BATTLING = register(Activity("battling"))
@JvmField
val ACTION_EFFECT = register(Activity("action_effect"))
@JvmField
val NPC_CHATTING = register(Activity("npc_chatting"))
@JvmField
val POKEMON_SLEEPING_ACTIVITY = register(Activity("pokemon_sleeping"))
@JvmField
val POKEMON_GROW_CROP = register(Activity("pokemon_grow_crop"))
@JvmField
val POKEMON_SLEEP_ON_TRAINER_BED = register(Activity("pokemon_sleep_on_trainer_bed"))
@JvmField
val POKEMON_HERD = register(Activity("pokemon_herd"))
@JvmField
val POKEMON_POLLINATION = register(Activity("pokemon_pollination"))
@JvmStatic
fun register(activity: Activity): Activity {
activities.add(activity)
return activity
@@ -60,13 +60,13 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
// Evolution Ores
@JvmField
val DAWN_STONE_ORE = evolutionStoneOre("dawn_stone_ore")
val DAWN_STONE_ORE = evolutionStoneOre("dawn_stone_ore", 7)
@JvmField
val DUSK_STONE_ORE = evolutionStoneOre("dusk_stone_ore")
@JvmField
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore", 10)
@JvmField
val NETHER_FIRE_STONE_ORE = evolutionStoneOre("nether_fire_stone_ore")
val NETHER_FIRE_STONE_ORE = this.create("nether_fire_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.NETHER).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).sound(SoundType.NETHER_ORE).lightLevel{10}))
@JvmField
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
@JvmField
@@ -74,24 +74,24 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val MOON_STONE_ORE = evolutionStoneOre("moon_stone_ore")
@JvmField
val DRIPSTONE_MOON_STONE_ORE = evolutionStoneOre("dripstone_moon_stone_ore")
val DRIPSTONE_MOON_STONE_ORE = this.create("dripstone_moon_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BROWN).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).sound(SoundType.DRIPSTONE_BLOCK)))
@JvmField
val SHINY_STONE_ORE = evolutionStoneOre("shiny_stone_ore")
val SHINY_STONE_ORE = evolutionStoneOre("shiny_stone_ore", 12)
@JvmField
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore", 2)
@JvmField
val TERRACOTTA_SUN_STONE_ORE = evolutionStoneOre("terracotta_sun_stone_ore")
val TERRACOTTA_SUN_STONE_ORE = this.create("terracotta_sun_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).lightLevel{2}))
@JvmField
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore", 6)
@JvmField
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
@JvmField
val DEEPSLATE_DAWN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dawn_stone_ore")
val DEEPSLATE_DAWN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dawn_stone_ore", 7)
@JvmField
val DEEPSLATE_DUSK_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dusk_stone_ore")
@JvmField
val DEEPSLATE_FIRE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_fire_stone_ore")
val DEEPSLATE_FIRE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_fire_stone_ore", 10)
@JvmField
val DEEPSLATE_ICE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_ice_stone_ore")
@JvmField
@@ -99,11 +99,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val DEEPSLATE_MOON_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_moon_stone_ore")
@JvmField
val DEEPSLATE_SHINY_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_shiny_stone_ore")
val DEEPSLATE_SHINY_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_shiny_stone_ore", 12)
@JvmField
val DEEPSLATE_SUN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_sun_stone_ore")
val DEEPSLATE_SUN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_sun_stone_ore", 2)
@JvmField
val DEEPSLATE_THUNDER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_thunder_stone_ore")
val DEEPSLATE_THUNDER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_thunder_stone_ore", 6)
@JvmField
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
@@ -454,7 +454,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val SOUL_CAMPFIRE = create("soul_campfire", CampfireBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.PODZOL).strength(2.0F).lightLevel{9}, true))
@JvmField
val RELIC_COIN_POUCH = create("relic_coin_pouch", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS).pushReaction(PushReaction.DESTROY).noOcclusion(), true))
@JvmField
@@ -577,74 +577,145 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
private val berries = mutableMapOf<ResourceLocation, BerryBlock>()
@JvmField
val AGUAV_BERRY = this.berryBlock("aguav")
@JvmField
val APICOT_BERRY = this.berryBlock("apicot")
@JvmField
val ASPEAR_BERRY = this.berryBlock("aspear")
@JvmField
val BABIRI_BERRY = this.berryBlock("babiri")
@JvmField
val BELUE_BERRY = this.berryBlock("belue")
@JvmField
val BLUK_BERRY = this.berryBlock("bluk")
@JvmField
val CHARTI_BERRY = this.berryBlock("charti")
@JvmField
val CHERI_BERRY = this.berryBlock("cheri")
@JvmField
val CHESTO_BERRY = this.berryBlock("chesto")
@JvmField
val CHILAN_BERRY = this.berryBlock("chilan")
@JvmField
val CHOPLE_BERRY = this.berryBlock("chople")
@JvmField
val COBA_BERRY = this.berryBlock("coba")
@JvmField
val COLBUR_BERRY = this.berryBlock("colbur")
@JvmField
val CORNN_BERRY = this.berryBlock("cornn")
@JvmField
val CUSTAP_BERRY = this.berryBlock("custap")
@JvmField
val DURIN_BERRY = this.berryBlock("durin")
@JvmField
val EGGANT_BERRY = this.berryBlock("eggant")
@JvmField
val ENIGMA_BERRY = this.berryBlock("enigma")
@JvmField
val FIGY_BERRY = this.berryBlock("figy")
@JvmField
val GANLON_BERRY = this.berryBlock("ganlon")
@JvmField
val GREPA_BERRY = this.berryBlock("grepa")
@JvmField
val HABAN_BERRY = this.berryBlock("haban")
@JvmField
val HONDEW_BERRY = this.berryBlock("hondew")
@JvmField
val HOPO_BERRY = this.berryBlock("hopo")
@JvmField
val IAPAPA_BERRY = this.berryBlock("iapapa")
@JvmField
val JABOCA_BERRY = this.berryBlock("jaboca")
@JvmField
val KASIB_BERRY = this.berryBlock("kasib")
@JvmField
val KEBIA_BERRY = this.berryBlock("kebia")
@JvmField
val KEE_BERRY = this.berryBlock("kee")
@JvmField
val KELPSY_BERRY = this.berryBlock("kelpsy")
@JvmField
val LANSAT_BERRY = this.berryBlock("lansat")
@JvmField
val LEPPA_BERRY = this.berryBlock("leppa")
@JvmField
val LIECHI_BERRY = this.berryBlock("liechi")
@JvmField
val LUM_BERRY = this.berryBlock("lum")
@JvmField
val MAGO_BERRY = this.berryBlock("mago")
@JvmField
val MAGOST_BERRY = this.berryBlock("magost")
@JvmField
val MARANGA_BERRY = this.berryBlock("maranga")
@JvmField
val MICLE_BERRY = this.berryBlock("micle")
@JvmField
val NANAB_BERRY = this.berryBlock("nanab")
@JvmField
val NOMEL_BERRY = this.berryBlock("nomel")
@JvmField
val OCCA_BERRY = this.berryBlock("occa")
@JvmField
val ORAN_BERRY = this.berryBlock("oran")
@JvmField
val PAMTRE_BERRY = this.berryBlock("pamtre")
@JvmField
val PASSHO_BERRY = this.berryBlock("passho")
@JvmField
val PAYAPA_BERRY = this.berryBlock("payapa")
@JvmField
val PECHA_BERRY = this.berryBlock("pecha")
@JvmField
val PERSIM_BERRY = this.berryBlock("persim")
@JvmField
val PETAYA_BERRY = this.berryBlock("petaya")
@JvmField
val PINAP_BERRY = this.berryBlock("pinap")
@JvmField
val POMEG_BERRY = this.berryBlock("pomeg")
@JvmField
val QUALOT_BERRY = this.berryBlock("qualot")
@JvmField
val RABUTA_BERRY = this.berryBlock("rabuta")
@JvmField
val RAWST_BERRY = this.berryBlock("rawst")
@JvmField
val RAZZ_BERRY = this.berryBlock("razz")
@JvmField
val RINDO_BERRY = this.berryBlock("rindo")
@JvmField
val ROSELI_BERRY = this.berryBlock("roseli")
@JvmField
val ROWAP_BERRY = this.berryBlock("rowap")
@JvmField
val SALAC_BERRY = this.berryBlock("salac")
@JvmField
val SHUCA_BERRY = this.berryBlock("shuca")
@JvmField
val SITRUS_BERRY = this.berryBlock("sitrus")
@JvmField
val SPELON_BERRY = this.berryBlock("spelon")
@JvmField
val STARF_BERRY = this.berryBlock("starf")
@JvmField
val TAMATO_BERRY = this.berryBlock("tamato")
@JvmField
val TANGA_BERRY = this.berryBlock("tanga")
@JvmField
val TOUGA_BERRY = this.berryBlock("touga")
@JvmField
val WACAN_BERRY = this.berryBlock("wacan")
@JvmField
val WATMEL_BERRY = this.berryBlock("watmel")
@JvmField
val WEPEAR_BERRY = this.berryBlock("wepear")
@JvmField
val WIKI_BERRY = this.berryBlock("wiki")
@JvmField
val YACHE_BERRY = this.berryBlock("yache")
//val BINDING_SOIL = this.create("binding_soil", BindingSoilBlock(BlockBehaviour.Properties.of()))
@@ -712,8 +783,10 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
}
private fun evolutionStoneOre(name: String) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.IRON_ORE)))
private fun evolutionStoneOre(name: String, lightLevel: Int) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.IRON_ORE).lightLevel { lightLevel }))
private fun deepslateEvolutionStoneOre(name: String) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.DEEPSLATE_IRON_ORE)))
private fun deepslateEvolutionStoneOre(name: String, lightLevel: Int) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.DEEPSLATE_IRON_ORE).lightLevel { lightLevel }))
/**
* Helper method for creating leaves
@@ -43,6 +43,7 @@ object CobblemonCosmeticItems : JsonDataRegistry<CosmeticItemAssignment> {
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.create()
@JvmField
val cosmeticItems = mutableListOf<CosmeticItemAssignment>()
override fun reload(data: Map<ResourceLocation, CosmeticItemAssignment>) {
@@ -55,7 +56,9 @@ object CobblemonCosmeticItems : JsonDataRegistry<CosmeticItemAssignment> {
CosmeticItemAssignmentSyncPacket(cosmeticItems).sendToPlayer(player)
}
@JvmStatic
fun findValidForPokemon(pokemon: Pokemon) = cosmeticItems.filter { it.pokemon.any { it.matches(pokemon) } }
@JvmStatic
fun findValidCosmeticForPokemonAndItem(registryAccess: RegistryAccess, pokemon: Pokemon, itemStack: ItemStack) = cosmeticItems
.filter { it.pokemon.any { it.matches(pokemon) } }
.flatMap { it.cosmeticItems }
@@ -21,56 +21,73 @@ import net.minecraft.resources.ResourceLocation
object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>, ResourceKey<Registry<DataComponentType<*>>>, DataComponentType<*>>() {
@JvmField
val POKEMON_ITEM: DataComponentType<PokemonItemComponent> = create("pokemon_item", DataComponentType.builder<PokemonItemComponent>()
.persistent(PokemonItemComponent.CODEC)
.networkSynchronized(PokemonItemComponent.PACKET_CODEC)
.build())
@JvmField
val HELD_ITEM_EFFECT: DataComponentType<HeldItemEffectComponent> = create("held_item_effect", DataComponentType.builder<HeldItemEffectComponent>()
.persistent(HeldItemEffectComponent.CODEC)
.networkSynchronized(HeldItemEffectComponent.PACKET_CODEC)
.build())
@JvmField
val BAIT: DataComponentType<RodBaitComponent> = create("bait", DataComponentType.builder<RodBaitComponent>()
.persistent(RodBaitComponent.CODEC)
.networkSynchronized(RodBaitComponent.PACKET_CODEC)
.build())
@JvmField
val POT_DATA: DataComponentType<PotComponent> = create("cooking_pot_item", DataComponentType.builder<PotComponent>()
.persistent(PotComponent.CODEC)
.networkSynchronized(PotComponent.PACKET_CODEC)
.build())
@JvmField
val BAIT_EFFECTS: DataComponentType<BaitEffectsComponent> = create("bait_effects", DataComponentType.builder<BaitEffectsComponent>()
.persistent(BaitEffectsComponent.CODEC)
.networkSynchronized(BaitEffectsComponent.PACKET_CODEC)
.build())
@JvmField
val FLAVOUR: DataComponentType<FlavourComponent> = create("flavour", DataComponentType.builder<FlavourComponent>()
.persistent(FlavourComponent.CODEC)
.networkSynchronized(FlavourComponent.PACKET_CODEC)
.build())
@JvmField
val RIDE_BOOST: DataComponentType<RideBoostsComponent> = create("ride_boosts", DataComponentType.builder<RideBoostsComponent>()
.persistent(RideBoostsComponent.CODEC)
.networkSynchronized(RideBoostsComponent.PACKET_CODEC)
.build())
@JvmField
val FOOD_COLOUR: DataComponentType<FoodColourComponent> = create("food_colour", DataComponentType.builder<FoodColourComponent>()
.persistent(FoodColourComponent.CODEC)
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
.build())
@JvmField
val INGREDIENT: DataComponentType<IngredientComponent> = create("ingredient", DataComponentType.builder<IngredientComponent>()
.persistent(IngredientComponent.CODEC)
.networkSynchronized(IngredientComponent.PACKET_CODEC)
.build())
@JvmField
val FOOD: DataComponentType<FoodComponent> = create("food", DataComponentType.builder<FoodComponent>()
.persistent(FoodComponent.CODEC)
.networkSynchronized(FoodComponent.PACKET_CODEC)
.build())
@JvmField
val MOB_EFFECTS: DataComponentType<MobEffectsComponent> = create("mob_effects", DataComponentType.builder<MobEffectsComponent>()
.persistent(MobEffectsComponent.CODEC)
.networkSynchronized(MobEffectsComponent.PACKET_CODEC)
.build())
@JvmField
val CRAFTED: DataComponentType<Boolean> = create("crafted", DataComponentType.builder<Boolean>()
.persistent(Codec.BOOL)
.networkSynchronized(ByteBufCodecs.BOOL)
@@ -82,6 +99,7 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:cooking_pot_item"), POT_DATA)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait_effects"), BAIT_EFFECTS)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:flavour"), FLAVOUR)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ride_boosts"), RIDE_BOOST)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food_colour"), FOOD_COLOUR)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ingredient"), INGREDIENT)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
@@ -36,7 +36,7 @@ import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.food.PonigiriItem
import com.cobblemon.mod.common.item.interactive.PonigiriItem
import com.cobblemon.mod.common.item.food.SinisterTeaItem
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
@@ -517,6 +517,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val RAWST_BERRY = berryItem("rawst", StatusCuringBerryItem(CobblemonBlocks.RAWST_BERRY, Statuses.BURN))
@JvmField val ASPEAR_BERRY = berryItem("aspear", StatusCuringBerryItem(CobblemonBlocks.ASPEAR_BERRY, Statuses.FROZEN))
@JvmField val PERSIM_BERRY = berryItem("persim", VolatileCuringBerryItem(CobblemonBlocks.PERSIM_BERRY, "confusion"))
@JvmField val EGGANT_BERRY = berryItem("eggant", VolatileCuringBerryItem(CobblemonBlocks.EGGANT_BERRY, "attract"))
@JvmField val RAZZ_BERRY = berryItem("razz", CobblemonBlocks.RAZZ_BERRY)
@JvmField val BLUK_BERRY = berryItem("bluk", CobblemonBlocks.BLUK_BERRY)
@JvmField val NANAB_BERRY = berryItem("nanab", CobblemonBlocks.NANAB_BERRY)
@@ -696,7 +697,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SUPERB_REMEDY = compostableItem("superb_remedy", RemedyItem(RemedyItem.SUPERB), 0.85f)
@JvmField
val MOOMOO_MILK = create("moomoo_milk", CobblemonItem(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
val MOOMOO_MILK = create("moomoo_milk", MoomooMilk(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
@JvmField
val POTION = create("potion", PotionItem(PotionType.POTION))
@@ -12,9 +12,11 @@ import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.data.DataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.mechanics.AprijuicesMechanic
import com.cobblemon.mod.common.mechanics.BerriesMechanic
import com.cobblemon.mod.common.mechanics.PotionsMechanic
import com.cobblemon.mod.common.mechanics.RemediesMechanic
import com.cobblemon.mod.common.net.messages.client.data.CobblemonMechanicsSyncPacket
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.cobblemonResource
@@ -37,13 +39,22 @@ object CobblemonMechanics : DataRegistry {
var remedies = RemediesMechanic()
var berries = BerriesMechanic()
var potions = PotionsMechanic()
var aprijuices = AprijuicesMechanic()
override fun sync(player: ServerPlayer) {}
override fun sync(player: ServerPlayer) {
CobblemonMechanicsSyncPacket(
this.remedies,
this.berries,
this.potions,
this.aprijuices,
).sendToPlayer(player)
}
override fun reload(manager: ResourceManager) {
remedies = loadMechanic(manager, "remedies", RemediesMechanic::class.java)
berries = loadMechanic(manager, "berries", BerriesMechanic::class.java)
potions = loadMechanic(manager, "potions", PotionsMechanic::class.java)
aprijuices = loadMechanic(manager, "aprijuices", AprijuicesMechanic::class.java)
}
private fun <T> loadMechanic(manager: ResourceManager, name: String, clazz: Class<T>): T {
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import net.minecraft.core.UUIDUtil
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import java.util.Optional
import java.util.UUID
import net.minecraft.core.BlockPos
import net.minecraft.core.GlobalPos
import net.minecraft.core.UUIDUtil
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import java.util.*
object CobblemonMemories {
val memories = mutableMapOf<String, MemoryModuleType<*>>()
@@ -30,46 +30,80 @@ object CobblemonMemories {
* get serialized during relogs. This makes sense for things like battles which
* do not survive a relog therefore any memory of it should be temporary.
*/
@JvmField
val BATTLING_POKEMON = register("battling_pokemon", ListCodec(UUIDUtil.CODEC, 0, 31))
@JvmField
val NPC_BATTLING = register("npc_battling", PrimitiveCodec.BOOL)
@JvmField
val DIALOGUES = register<List<ActiveDialogue>>("npc_dialogues")
@JvmField
val ACTIVE_ACTION_EFFECT = register<ActionEffectContext>("active_action_effect")
@JvmField
val POKEMON_FLYING = register("pokemon_flying", PrimitiveCodec.BOOL)
@JvmField
val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL)
@JvmField
val POKEMON_SLEEPING = register("pokemon_sleeping", PrimitiveCodec.BOOL)
@JvmField
val POKEMON_BATTLE = register<UUID>("pokemon_battle")
@JvmField
val PATH_COOLDOWN = register<Boolean>("path_cooldown")
@JvmField
val TARGETED_BATTLE_POKEMON = register<UUID>("targeted_battle_pokemon")
@JvmField
val NEAREST_VISIBLE_ATTACKER = register<LivingEntity>("nearest_visible_attacker")
@JvmField
val NEARBY_GROWABLE_CROPS = register<BlockPos>("nearby_growable_crops")
@JvmField
val NEARBY_SWEET_BERRY_BUSH = register<BlockPos>("nearest_sweet_berry_bush")
@JvmField
val DISABLE_WALK_TO_BERRY_BUSH = register<Boolean>("disable_walk_to_berry_bush")
@JvmField
val TIME_TRYING_TO_REACH_BERRY_BUSH = register<Int>("time_trying_to_reach_berry_bush")
@JvmField
val IS_CONSUMING_ITEM = register<Boolean>("is_consuming_item")
@JvmField
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
val HIVE_LOCATION = register<BlockPos>("hive_location")
@JvmField
val HIVE_LOCATION = register<BlockPos>("hive_location", BlockPos.CODEC)
@JvmField
val HIVE_BLACKLIST = register<List<BlockPos>>("hive_blacklist")
@JvmField
val HIVE_COOLDOWN = register<Boolean>("hive_cooldown")
val NEARBY_FLOWERS = register<List<BlockPos>>("nearby_flower")
val POLLINATED = register<Boolean>("pollinated", PrimitiveCodec.BOOL)
@JvmField
val NEARBY_FLOWER = register<BlockPos>("nearby_flower", BlockPos.CODEC)
@JvmField
val PATH_TO_NEARBY_FLOWER_COOLDOWN = register<Boolean>("path_to_nearby_flower_cooldown")
@JvmField
val HAS_NECTAR = register<Boolean>("has_nectar", PrimitiveCodec.BOOL)
@JvmField
val NEARBY_SACC_LEAVES = register<BlockPos>("nearby_sacc_leaves", BlockPos.CODEC)
/** who am i following rn? */
@JvmField
val HERD_LEADER = register<String>("herd_leader", PrimitiveCodec.STRING)
/** how many are following me rn? */
@JvmField
val HERD_SIZE = register<Int>("herd_size") // Don't bother saving it, we'll try to keep count roughly.
@JvmField
val ATTACK_TARGET_DATA = register<CobblemonAttackTargetData>("attack_target_data") // This is used to store additional information about the attack target, such as when to give up pursuit.
@JvmField
val WANDER_CONTROL = register<CobblemonWanderControl>("wander_control")
@JvmField
val DISABLE_WALK_TO_WANTED_ITEM = register<Boolean>("disable_walk_to_wanted_item")
@JvmField
val TIME_TRYING_TO_REACH_WANTED_ITEM = register<Int>("time_trying_to_wanted_item")
@JvmStatic
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
val memoryModule = MemoryModuleType(Optional.of(codec))
memories[id] = memoryModule
return memoryModule
}
@JvmStatic
fun <U> register(id: String): MemoryModuleType<U> {
val memoryModule = MemoryModuleType<U>(Optional.empty())
memories[id] = memoryModule
return memoryModule
}
}
}
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
import com.cobblemon.mod.common.client.net.data.CobblemonMechanicsSyncHandler
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
@@ -28,12 +29,13 @@ import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
import com.cobblemon.mod.common.client.net.orientation.S2CUpdateOrientationHandler
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
@@ -132,6 +134,7 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotification
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
@@ -179,6 +182,7 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePa
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
@@ -216,7 +220,7 @@ import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandle
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
import com.cobblemon.mod.common.net.serverhandling.orientation.OrientationPacketHandler
import com.cobblemon.mod.common.net.serverhandling.orientation.ServerboundUpdateOrientationHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.SetPastureConflictHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
@@ -231,6 +235,7 @@ import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHan
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdateRiderRotationHandler
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
@@ -263,10 +268,13 @@ object CobblemonNetwork {
fun ServerPlayer.sendPacket(packet: NetworkPacket<*>) {
sendPacketToPlayer(this, packet)
}
@JvmStatic
fun sendToServer(packet: NetworkPacket<*>) {
Cobblemon.implementation.networkManager.sendToServer(packet)
}
@JvmStatic
fun sendToAllPlayers(packet: NetworkPacket<*>) = sendPacketToPlayers(server()!!.playerList.players, packet)
@JvmStatic
fun sendPacketToPlayers(players: Iterable<ServerPlayer>, packet: NetworkPacket<*>) = players.forEach { sendPacketToPlayer(it, packet) }
val s2cPayloads = generateS2CPacketInfoList()
@@ -345,6 +353,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(InteractPokemonUIPacket.ID, InteractPokemonUIPacket::decode, InteractPokemonUIPacketHandler))
list.add(PacketRegisterInfo(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler))
list.add(PacketRegisterInfo(PokedexUIPacket.ID, PokedexUIPacket::decode, PokedexUIPacketHandler))
list.add(PacketRegisterInfo(ExpGainedDataPacket.ID, ExpGainedDataPacket::decode, ExpGainedDataPacketHandler))
// Starter packets
list.add(PacketRegisterInfo(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler))
@@ -387,6 +396,7 @@ object CobblemonNetwork {
// Data registries
list.add(PacketRegisterInfo(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(CobblemonMechanicsSyncPacket.ID, CobblemonMechanicsSyncPacket::decode, CobblemonMechanicsSyncHandler))
list.add(PacketRegisterInfo(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
@@ -442,7 +452,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(UpdatePastureConflictFlagPacket.ID, UpdatePastureConflictFlagPacket::decode, UpdatePastureConflictFlagHandler))
// Orientation
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, ClientboundUpdateOrientationHandler))
// Behaviours
list.add(PacketRegisterInfo(PlayPosableAnimationPacket.ID, PlayPosableAnimationPacket::decode, PlayPosableAnimationHandler))
@@ -577,13 +587,14 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
// Riding packet(s)
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, ServerboundUpdateOrientationHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingSettingsPacket.ID, ServerboundUpdateRidingSettingsPacket::decode, ServerboundUpdateRidingSettingsHandler))
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
list.add(PacketRegisterInfo(ServerboundUpdateDriverInputPacket.ID, ServerboundUpdateDriverInputPacket::decode, DriverInputPacketHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRiderRotationPacket.ID, ServerboundUpdateRiderRotationPacket::decode, ServerboundUpdateRiderRotationHandler))
// Cooking
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
@@ -598,4 +609,4 @@ object CobblemonNetwork {
fun sendPacketToPlayer(player: ServerPlayer, packet: NetworkPacket<*>) {
Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
}
}
}
@@ -26,8 +26,6 @@ object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Regist
@JvmField
val NURSE_KEY = createKey("nurse", CobblemonBlocks.HEALING_MACHINE, 1, 1)
@JvmField
val POKE_SNACK_KEY = createKey("poke_snack", CobblemonBlocks.POKE_SNACK, 0, 1)
@JvmField
val SACCHARINE_LOG_SLATHERED_KEY = createKey("saccharine_log_slathered", CobblemonBlocks.SACCHARINE_LOG_SLATHERED, 0, 1)
// TODO after 1.7
// @JvmField
@@ -26,6 +26,7 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatSettings
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstSettings
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinSettings
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineSettings
import com.cobblemon.mod.common.net.messages.client.data.RideSettingsSyncPacket
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
@@ -63,6 +64,7 @@ object CobblemonRideSettings : DataRegistry {
var boat = BoatSettings()
var burst = BurstSettings()
var dolphin = DolphinSettings()
var submarine = SubmarineSettings()
override fun sync(player: ServerPlayer) {
player.sendPacket(
@@ -78,7 +80,8 @@ object CobblemonRideSettings : DataRegistry {
vehicle = vehicle,
boat = boat,
burst = burst,
dolphin = dolphin
dolphin = dolphin,
submarine = submarine
)
)
}
@@ -96,6 +99,7 @@ object CobblemonRideSettings : DataRegistry {
boat = loadStyle(manager, "boat", BoatSettings::class.java)
burst = loadStyle(manager, "burst", BurstSettings::class.java)
dolphin = loadStyle(manager, "dolphin", DolphinSettings::class.java)
submarine = loadStyle(manager, "submarine", SubmarineSettings::class.java)
}
private fun <T : RidingBehaviourSettings> loadStyle(manager: ResourceManager, name: String, clazz: Class<T>): T {
@@ -20,30 +20,45 @@ import net.minecraft.world.entity.ai.sensing.SensorType
object CobblemonSensors {
val sensors = mutableMapOf<String, SensorType<*>>()
@JvmField
val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
@JvmField
val BATTLING_POKEMON = register("battling_pokemon", ::BattlingPokemonSensor)
// val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
@JvmField
val POKEMON_DROWSY = register("pokemon_drowsy", ::DrowsySensor)
@JvmField
val POKEMON_ADULT = register("pokemon_adult_sensor", ::PokemonAdultSensor)
@JvmField
val POKEMON_DISTURBANCE = register("pokemon_disturbance_sensor", ::PokemonDisturbancesSensor)
@JvmField
val POKEMON_DEFEND_OWNER = register("pokemon_owner_under_attack", ::DefendOwnerSensor)
@JvmField
val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops", ::PokemonGrowableCropSensor)
@JvmField
val NEARBY_BEE_HIVE = register("nearby_bee_hive", ::BeeHiveSensor)
@JvmField
val NEARBY_FLOWER = register("nearby_flower", ::FlowerSensor)
@JvmField
val NEARBY_SWEET_BERRY_BUSH = register("nearby_sweet_berry_bush", ::SweetBerryBushSensor)
@JvmField
val POKEMON_NEARBY_WANTED_ITEM = register("pokemon_nearby_wanted_item", ::PokemonItemSensor)
@JvmField
val NEARBY_SACC_LEAVES = register("nearby_sacc_leaves", ::SacLeavesSensor)
@JvmStatic
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
val sensor = SensorType(supplier)
sensors[id] = sensor
return sensor
}
}
}
@@ -103,6 +103,11 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val EVOLUTION = this.create("evolution.full")
@JvmField
val LEVELUP_START = this.create("gui.levelup_start")
@JvmField
val LEVELUP = this.create("gui.levelup")
@JvmField
val PVN_BATTLE = this.create("battle.pvn.default")
@JvmField
@@ -23,43 +23,61 @@ import net.minecraft.resources.ResourceKey
* @since October 26th, 2022
*/
object CobblemonCriteria : PlatformRegistry<Registry<CriterionTrigger<*>>, ResourceKey<Registry<CriterionTrigger<*>>>, CriterionTrigger<*>>(){
@JvmField
val PICK_STARTER = this.create("pick_starter", SimpleCriterionTrigger(PokemonCriterion.CODEC))
@JvmField
val CATCH_POKEMON = this.create("catch_pokemon", SimpleCriterionTrigger(CaughtPokemonCriterion.CODEC))
@JvmField
val CATCH_SHINY_POKEMON = this.create("catch_shiny_pokemon", SimpleCriterionTrigger(CountableCriterion.CODEC))
@JvmField
val EGG_COLLECT = this.create("eggs_collected", SimpleCriterionTrigger(CountableCriterion.CODEC))
@JvmField
val EGG_HATCH = this.create("eggs_hatched", SimpleCriterionTrigger(CountableCriterion.CODEC))
@JvmField
val EVOLVE_POKEMON = this.create("pokemon_evolved", SimpleCriterionTrigger(EvolvePokemonCriterion.CODEC))
@JvmField
val WIN_BATTLE = this.create("battles_won", SimpleCriterionTrigger(BattleCountableCriterion.CODEC))
@JvmField
val DEFEAT_POKEMON = this.create("pokemon_defeated", SimpleCriterionTrigger(CountableCriterion.CODEC))
@JvmField
val COLLECT_ASPECT = this.create("aspects_collected", SimpleCriterionTrigger(AspectCriterion.CODEC))
@JvmField
val POKEMON_INTERACT = this.create("pokemon_interact", SimpleCriterionTrigger(PokemonInteractCriterion.CODEC))
@JvmField
val PARTY_CHECK = this.create("party", SimpleCriterionTrigger(PartyCheckCriterion.CODEC))
@JvmField
val LEVEL_UP = this.create("level_up", SimpleCriterionTrigger(LevelUpCriterion.CODEC))
@JvmField
val PASTURE_USE = this.create("pasture_use", SimpleCriterionTrigger(PokemonCriterion.CODEC))
@JvmField
val RESURRECT_POKEMON = this.create("resurrect_pokemon", SimpleCriterionTrigger(PokemonCriterion.CODEC))
@JvmField
val TRADE_POKEMON = this.create("trade_pokemon", SimpleCriterionTrigger(TradePokemonCriterion.CODEC))
@JvmField
val CAST_POKE_ROD = this.create("cast_poke_rod", SimpleCriterionTrigger(CastPokeRodCriterionCondition.CODEC))
@JvmField
val REEL_IN_POKEMON = this.create("reel_in_pokemon", SimpleCriterionTrigger(ReelInPokemonCriterionCondition.CODEC))
// Advancement criteria for [grow_tumblestone.json]
@JvmField
val PLANT_TUMBLESTONE = this.create("plant_tumblestone", SimpleCriterionTrigger(PlantTumblestoneCriterion.CODEC))
override val registry = BuiltInRegistries.TRIGGER_TYPES
override val resourceKey = Registries.TRIGGER_TYPE
}
}
@@ -22,18 +22,19 @@ class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceL
class ReelInPokemonCriterionCondition(
playerCtx: Optional<ContextAwarePredicate>,
val species: String,
val baitId: String
val baitId: String // also allows "cobblemon:empty_bait" to indicate that no bait is allowed for this criterion to match
) : SimpleCriterionCondition<ReelInPokemonContext>(playerCtx) {
companion object {
val CODEC: Codec<ReelInPokemonCriterionCondition> = RecordCodecBuilder.create { it.group(
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter { it.playerCtx },
Codec.STRING.optionalFieldOf("species", "any").forGetter { it.species },
Codec.STRING.optionalFieldOf("baitId", "empty_bait").forGetter { it.baitId }
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId.ifEmpty { "empty_bait" }) }) }
Codec.STRING.optionalFieldOf("baitId", "any").forGetter { it.baitId }
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId) }) }
}
override fun matches(player: ServerPlayer, context: ReelInPokemonContext): Boolean {
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any")
&& (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "any")
}
}
@@ -70,16 +70,23 @@ object Abilities : DataRegistry {
AbilityRegistrySyncPacket(all()).sendToPlayer(player)
}
@JvmStatic
fun register(ability: AbilityTemplate): AbilityTemplate {
this.abilityMap[ability.name.lowercase()] = ability
return ability
}
@JvmStatic
fun all() = this.abilityMap.values.toList()
@JvmStatic
fun first() = this.abilityMap.values.first()
@JvmStatic
fun get(name: String) = abilityMap[name.lowercase()]
@JvmStatic
fun getOrDummy(name: String) = get(name) ?: DUMMY
@JvmStatic
fun getOrException(name: String) = get(name) ?: throw IllegalArgumentException("Unable to find ability of name: $name")
@JvmStatic
fun count() = this.abilityMap.size
internal fun receiveSyncPacket(abilities: Collection<AbilityTemplate>) {
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.Behavior
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.schedule.Activity
/**
* A [Behavior] subclass that represents tasks that check that the entity is still in one
* of the activities that this task is part of. If the entity is no longer doing any of those
* activities, the task will be interrupted and you can handle any cleanup in [onInterrupted].
*
* @author Hiroku
* @since October 17th, 2025
*/
abstract class ActivityAwareBehavior<E : LivingEntity> : Behavior<E> {
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>) : super(entryCondition)
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>, duration: Int) : super(entryCondition, duration)
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>, minDuration: Int, maxDuration: Int) : super(entryCondition, minDuration, maxDuration)
val activities: MutableSet<Activity> = mutableSetOf()
fun isStillDoingActivity(entity: E): Boolean {
return activities.any(entity.brain::isActive)
}
override fun canStillUse(level: ServerLevel, entity: E, gameTime: Long) = isStillDoingActivity(entity)
open fun onInterrupted(level: ServerLevel, entity: E, gameTime: Long) {
// No-op
}
override fun stop(level: ServerLevel, entity: E, gameTime: Long) {
super.stop(level, entity, gameTime)
if (!isStillDoingActivity(entity)) {
onInterrupted(level, entity, gameTime)
}
}
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.ai
import com.google.common.collect.ImmutableList
import com.mojang.datafixers.util.Pair
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.schedule.Activity
@@ -23,6 +22,13 @@ class ActivityConfigurationContext(val activity: Activity) {
}
fun apply(entity: LivingEntity) {
tasks.forEach {
val activityAwareBehavior = it.second as? ActivityAwareBehavior<*>
?: (it.second as? WrapperLivingEntityTask<*>)?.task as? ActivityAwareBehavior
?: return@forEach
activityAwareBehavior.activities += activity
}
entity.brain.addActivity(activity, ImmutableList.copyOf(tasks))
}
}
@@ -47,12 +47,23 @@ class ApplyBehaviours : BehaviourConfig {
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
if (!checkCondition(behaviourConfigurationContext, condition)) return
val configurations = behaviours.map { CobblemonBehaviours.behaviours[it]?.takeIf { it.canBeApplied(entity) } ?: return Cobblemon.LOGGER.warn("Behaviour $it not found") }
val applicableBehaviours = behaviours.mapNotNull {
val resolvedBehaviour = CobblemonBehaviours.behaviours[it]
if (resolvedBehaviour == null) {
Cobblemon.LOGGER.warn("Behaviour $it not found while configuring entity of type ${entity.type}")
} else if (!resolvedBehaviour.canBeApplied(entity)) {
Cobblemon.LOGGER.warn("Behaviour $it cannot be applied to entity ${entity.id}")
} else {
return@mapNotNull resolvedBehaviour
}
null
}
// Why not just add the presets to the context directly?
// Nested preset application is a thing, and I only want to track the top level presets.
// i.e. if a preset applies another preset, I don't want to track the inner preset, since it's redundant if we track the top one.
val originalContextBehaviours = behaviourConfigurationContext.appliedBehaviours.toMutableSet()
configurations.forEach {
applicableBehaviours.forEach {
it.configure(entity, behaviourConfigurationContext)
}
originalContextBehaviours.addAll(behaviours)
@@ -23,7 +23,7 @@ import net.minecraft.world.entity.schedule.Activity
class ActivityChangeTaskConfig : SingleTaskConfig {
val activity: Activity = Activity.IDLE
val condition: ExpressionLike = "false".asExpressionLike()
val condition: ExpressionLike = "true".asExpressionLike()
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): List<MoLangConfigVariable> = emptyList()
@@ -11,8 +11,7 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.SEE_DISTANCE
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.util.resolveEntityTypes
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget
@@ -22,13 +21,16 @@ import net.minecraft.world.entity.ai.sensing.SensorType
class LookAtEntitiesTaskConfig : SingleTaskConfig {
companion object {
const val LOOK_AT_ENTITIES = "look_at_entities"
const val LOOK_AT_ENTITY_TYPES = "look_at_entity_types"
}
val condition = booleanVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITIES, true).asExpressible()
val maxDistance = numberVariable(SharedEntityVariables.LOOKING_CATEGORY, SEE_DISTANCE, 15).asExpressible()
val entityTypes = stringVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITY_TYPES, "").asExpressible()
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
condition,
entityTypes,
maxDistance
).asVariables()
@@ -39,6 +41,18 @@ class LookAtEntitiesTaskConfig : SingleTaskConfig {
if (!condition.resolveBoolean(behaviourConfigurationContext.runtime)) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.LOOK_TARGET)
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
return SetEntityLookTarget.create(maxDistance.resolveFloat(behaviourConfigurationContext.runtime))
val lookDistance = maxDistance.resolveFloat(behaviourConfigurationContext.runtime)
val lookAtTypesText = entityTypes.resolveString(behaviourConfigurationContext.runtime)
if (lookAtTypesText.isBlank()) {
return SetEntityLookTarget.create(lookDistance)
}
val lookAtTypes = resolveEntityTypes(entity.registryAccess(), lookAtTypesText)
return if (lookAtTypes.isNotEmpty()) {
SetEntityLookTarget.create({ lookAtTypes.contains(it.type) }, lookDistance)
} else {
null
}
}
}
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.getMemorySafely
import com.cobblemon.mod.common.util.resolveString
import com.mojang.datafixers.util.Either
import net.minecraft.server.level.ServerLevel
@@ -62,7 +63,7 @@ class MemoryAspectTaskConfig : SingleTaskConfig {
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long) = true
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
val hasMemory = !owner.brain.hasMemoryValue(memory)
val hasMemory = owner.brain.hasMemoryValue(memory)
if (owner is PokemonEntity) {
if (!hasMemory && aspect in owner.pokemon.forcedAspects) {
owner.pokemon.forcedAspects -= aspect
@@ -38,7 +38,7 @@ class MoveToOwnerTaskConfig : SingleTaskConfig {
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
): BehaviorControl<in LivingEntity> {
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
MemoryModuleType.LOOK_TARGET
@@ -8,16 +8,31 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonSensors
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToBeeHiveTask
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
import com.cobblemon.mod.common.util.distanceTo
import com.cobblemon.mod.common.util.getMemorySafely
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.Behavior
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.memory.WalkTarget
import net.minecraft.world.phys.Vec3
class PathToBeeHiveTaskConfig : SingleTaskConfig {
companion object {
const val HONEY = "honey"
const val STAY_OUT_OF_HIVE_COOLDOWN = 400
}
val condition = booleanVariable(HONEY, "can_add_honey", true).asExpressible()
@@ -36,6 +51,107 @@ class PathToBeeHiveTaskConfig : SingleTaskConfig {
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
return null
}
return PathToBeeHiveTask.create()
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE)
return object : Behavior<LivingEntity>(
mapOf(
MemoryModuleType.LOOK_TARGET to MemoryStatus.REGISTERED,
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
CobblemonMemories.HIVE_LOCATION to MemoryStatus.VALUE_PRESENT,
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
CobblemonMemories.HIVE_BLACKLIST to MemoryStatus.REGISTERED,
),
400,
400
) {
val maxTicks = 400
var traveledTicks = 0
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
return (owner is PathfinderMob && owner.isAlive && (owner is PokemonEntity && PlaceHoneyInHiveTask.wantsToEnterHive(owner))) && owner.brain.checkMemory(
MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)
}
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
if (maxTicks >= traveledTicks) return false
val pos = entity.brain.getMemory(CobblemonMemories.HIVE_LOCATION)
return !pos.isEmpty && entity.distanceTo(pos.get()) > 1.0
}
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
super.start(level, entity, gameTime)
val hiveLocation = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
val world = entity.level()
val sidesByClosest = listOf(
hiveLocation.north(),
hiveLocation.south(),
hiveLocation.east(),
hiveLocation.west()
).sortedBy { it.distSqr(entity.blockPosition()) }
var openSide = BlockPos.ZERO
for (side in sidesByClosest) {
if (world.getBlockState(side).isAir) {
openSide = side
break
}
}
if (openSide == BlockPos.ZERO) {
if (world.getBlockState(hiveLocation.above()).isAir) {
// If the above position is also air, we can use it
openSide = hiveLocation.above() // Fallback to above if no open sides found
} else if (world.getBlockState(hiveLocation.below()).isAir) {
// If the below position is also air, we can use it
openSide = hiveLocation.below() // Fallback to below if no open sides found
} else {
// If no open sides or above/below positions are found, we cannot proceed
return
}
}
val targetVec = Vec3.atCenterOf(openSide)
// Set path target toward hive
if (pathfindDirectlyTowards(openSide, entity)) {
entity.brain.setMemory(MemoryModuleType.WALK_TARGET,WalkTarget(targetVec, 0.35F, 0))
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET,BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
traveledTicks = 0
} else {
dropAndBlackListHive(entity)
}
}
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
traveledTicks++
}
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
if (maxTicks < traveledTicks) {
dropAndBlackListHive(entity)
entity.brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, 100)
}
}
fun dropAndBlackListHive(entity: LivingEntity) {
val hivePos = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
if (hivePos == null) return
val blackList = entity.brain.getMemorySafely(CobblemonMemories.HIVE_BLACKLIST).orElse(emptyList()).toMutableList()
blackList.add(hivePos)
if (blackList.count() > 3) {
blackList.removeFirst()
}
entity.brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
entity.brain.setMemory(CobblemonMemories.HIVE_BLACKLIST, blackList)
}
private fun pathfindDirectlyTowards(pos: BlockPos, entity: LivingEntity): Boolean {
if (entity !is PathfinderMob) return false
val nav = entity.navigation
val path = nav. createPath(pos, 0)
return path != null && path.canReach()
}
}
}
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonSensors
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
@@ -41,12 +40,14 @@ class PathToFlowerTaskConfig : SingleTaskConfig {
return null
}
behaviourConfigurationContext.addMemories(
CobblemonMemories.NEARBY_FLOWERS,
CobblemonMemories.NEARBY_FLOWER,
CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN,
CobblemonMemories.HIVE_COOLDOWN,
CobblemonMemories.HIVE_LOCATION,
CobblemonMemories.POLLINATED
CobblemonMemories.HIVE_BLACKLIST,
CobblemonMemories.HAS_NECTAR,
)
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE, CobblemonSensors.NEARBY_FLOWER)
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_FLOWER)
return PathToFlowerTask.create()
}
}
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonSensors
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToSacLeafTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class PathToSaccLeavesTaskConfig : SingleTaskConfig {
companion object {
const val POLLINATE = "pollinate"
}
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
condition
).asVariables()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
if (entity !is PokemonEntity) {
return null
}
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
return null
}
behaviourConfigurationContext.addMemories(
CobblemonMemories.NEARBY_SACC_LEAVES,
CobblemonMemories.HAS_NECTAR
)
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_SACC_LEAVES, CobblemonSensors.NEARBY_FLOWER)
return PathToSacLeafTask.create()
}
}
@@ -8,8 +8,8 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
@@ -37,6 +37,9 @@ class PlaceHoneyInHiveTaskConfig : SingleTaskConfig {
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
return null
}
return PlaceHoneyInHiveTask.create()
return WrapperLivingEntityTask(
PlaceHoneyInHiveTask.create(),
PokemonEntity::class.java
)
}
}
@@ -0,0 +1,130 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonActivities
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.block.SaccharineLeafBlock
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.getMemorySafely
import net.minecraft.server.level.ServerLevel
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.Behavior
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.phys.Vec3
class PlaceHoneyInSaccLeavesTaskConfig : SingleTaskConfig {
companion object {
const val POLLINATE = "pollinate"
const val MIN_DURATION : Int = 300
const val MAX_DURATION : Int = 400
const val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 250
}
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
condition
).asVariables()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
if (entity !is PokemonEntity) {
return null
}
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
return null
}
return object : Behavior<LivingEntity>(
mapOf(
CobblemonMemories.NEARBY_SACC_LEAVES to MemoryStatus.VALUE_PRESENT,
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
CobblemonMemories.HAS_NECTAR to MemoryStatus.VALUE_PRESENT,
),
MIN_DURATION,
MAX_DURATION
) {
var successfulPollinationTicks = 0
var lastSoundPlayedTick = 0
var hoverPos: Vec3? = null
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
if (level.isNight || level.isRaining || !(entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false))) return false
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES)
if (!optionalBlockPos.isPresent || level.getBlockState(optionalBlockPos.get()).block != CobblemonBlocks.SACCHARINE_LEAVES) return false
return Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 0.6
}
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
CobblemonActivities.POKEMON_POLLINATION) != -1
}
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
super.start(level, entity, gameTime)
hoverPos = null
}
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
++successfulPollinationTicks
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
this.lastSoundPlayedTick = successfulPollinationTicks
entity.playSound(SoundEvents.BEEHIVE_DRIP, 1.0f, 1.0f)
}
val leavesPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
val bl3 = entity.random.nextInt(40) == 0
if (bl && bl3) {
// mimics the wriggling over a flower the vanilla bees do
if (hoverPos == null) {
hoverPos = leavesPos.bottomCenter.add(0.0, 0.4, 0.0)
}
if (leavesPos != null) {
hoverPos = leavesPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
entity.getMoveControl()
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
entity.lookControl.setLookAt(leavesPos.bottomCenter.add(0.0,0.5,0.0))
}
} else if (!bl) {
entity.getMoveControl()
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
}
}
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
val blockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
blockPos?.let {
val blockState = level.getBlockState(blockPos)
if (blockState.block == CobblemonBlocks.SACCHARINE_LEAVES) {
val saccAge = blockState.getValue( SaccharineLeafBlock.AGE)
if (saccAge < SaccharineLeafBlock.MAX_AGE) {
entity.brain.eraseMemory(CobblemonMemories.HAS_NECTAR)
val newBlockState = blockState.setValue(SaccharineLeafBlock.AGE, saccAge + 1)
level.setBlock(blockPos, newBlockState, 3)
}
}
}
}
successfulPollinationTicks = 0
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
}
}
}
}
@@ -8,17 +8,14 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonActivities
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.getMemorySafely
import com.cobblemon.mod.common.util.sendParticlesServer
import com.mojang.datafixers.util.Either
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.server.level.ServerLevel
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.Behavior
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -29,10 +26,11 @@ import net.minecraft.world.phys.Vec3
class PollinateFlowerTaskConfig : SingleTaskConfig {
companion object {
const val POLLINATE = "pollinate"
const val PATH_TO_FLOWER_COOLDOWN_TICKS : Long = 200
const val HAS_NECTAR_ASPECT = "has_nectar"
}
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
val durationTicks: ExpressionOrEntityVariable = Either.left("30".asExpression())
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
condition
@@ -51,22 +49,28 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
return object : Behavior<LivingEntity>(
mapOf(
CobblemonMemories.NEARBY_FLOWERS to MemoryStatus.VALUE_PRESENT,
CobblemonMemories.NEARBY_FLOWER to MemoryStatus.VALUE_PRESENT,
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
CobblemonMemories.POLLINATED to MemoryStatus.VALUE_ABSENT,
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
),
15,
45
600,
625
) {
val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 400
var successfulPollinationTicks = 0
var lastSoundPlayedTick = 0
var hoverPos: Vec3? = null
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
return entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWERS).orElse(emptyList()).any {
Vec3.atCenterOf(it).distanceTo(entity.position()) <= 1.0
}
if (level.isNight || level.isRaining || entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false)) return false
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER)
return optionalBlockPos.isPresent && Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 1.0
}
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
return checkExtraStartConditions(level, entity)
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
CobblemonActivities.POKEMON_POLLINATION) != -1
}
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
@@ -74,20 +78,44 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
}
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
level.sendParticlesServer(
particleType = ParticleTypes.DRIPPING_HONEY,
position = owner.eyePosition,
particles = 3,
offset = Vec3.ZERO,
speed = 0.0
)
++successfulPollinationTicks
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
this.lastSoundPlayedTick = successfulPollinationTicks
entity.playSound(SoundEvents.BEE_POLLINATE, 1.0f, 1.0f)
}
val flowerPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER).orElse(null)
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
val bl3 = entity.random.nextInt(40) == 0
if (bl && bl3) {
// mimics the wriggling over a flower the vanilla bees do
if (hoverPos == null) {
hoverPos = flowerPos.bottomCenter.add(0.0, 0.4, 0.0)
}
if (flowerPos != null) {
hoverPos = flowerPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
entity.getMoveControl()
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
}
} else if (!bl) {
entity.getMoveControl()
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
}
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
}
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
val flowerStillThere = canStillUse(level, entity, gameTime)
if (flowerStillThere) {
entity.brain.setMemory(CobblemonMemories.POLLINATED, true)
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
entity.brain.setMemory(CobblemonMemories.HAS_NECTAR, true)
}
successfulPollinationTicks = 0
entity.brain.setMemoryWithExpiry(CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN, true, PATH_TO_FLOWER_COOLDOWN_TICKS)
}
}
}
@@ -97,7 +97,9 @@ interface TaskConfig {
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
cobblemonResource("path_to_hive") to PathToBeeHiveTaskConfig::class.java,
cobblemonResource("place_honey_in_hive") to PlaceHoneyInHiveTaskConfig::class.java,
cobblemonResource("place_honey_in_sacc_leaves") to PlaceHoneyInSaccLeavesTaskConfig::class.java,
cobblemonResource("path_to_flower") to PathToFlowerTaskConfig::class.java,
cobblemonResource("path_to_sacc_leaves") to PathToSaccLeavesTaskConfig::class.java,
cobblemonResource("pollinate_flower") to PollinateFlowerTaskConfig::class.java,
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
cobblemonResource("manage_flight_in_battle") to ManageFlightInBattleTaskConfig::class.java,
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.apricorn
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.block.ApricornBlock
import com.cobblemon.mod.common.block.ApricornSaplingBlock
import com.cobblemon.mod.common.item.ApricornItem
@@ -28,43 +27,14 @@ import net.minecraft.world.level.material.MapColor
* @author Licious
* @since October 29th, 2022
*/
enum class Apricorn(
/** A value of true means it buffs that flavour, a value of false means it weakens that flavour. */
val flavourStrength: Map<Flavour, Boolean> = emptyMap()
) : StringRepresentable {
enum class Apricorn : StringRepresentable {
BLACK,
BLUE(
mapOf(
Flavour.DRY to true,
Flavour.BITTER to false
)
),
GREEN(
mapOf(
Flavour.BITTER to true,
Flavour.SWEET to false
)
),
PINK(
mapOf(
Flavour.SWEET to true,
Flavour.SPICY to false
)
),
RED(
mapOf(
Flavour.SPICY to true,
Flavour.SOUR to false
)
),
BLUE,
GREEN,
PINK,
RED,
WHITE,
YELLOW(
mapOf(
Flavour.SOUR to true,
Flavour.DRY to false
)
);
YELLOW;
fun item(): ApricornItem = when(this) {
BLACK -> CobblemonItems.BLACK_APRICORN
@@ -131,5 +101,4 @@ enum class Apricorn(
companion object {
val CODEC: Codec<Apricorn> = StringRepresentable.fromValues(::values)
}
}
@@ -85,6 +85,7 @@ object Berries : JsonDataRegistry<Berry> {
BerryRegistrySyncPacket(this.all()).sendToPlayer(player)
}
@JvmStatic
fun all() = this.berries.values.toList()
/**
@@ -93,6 +94,7 @@ object Berries : JsonDataRegistry<Berry> {
* @param identifier The identifier of the berry.
* @return The [Berry] if loaded otherwise null.
*/
@JvmStatic
fun getByIdentifier(identifier: ResourceLocation): Berry? = this.berries[identifier]
/**
@@ -101,6 +103,7 @@ object Berries : JsonDataRegistry<Berry> {
* @param name The path of the identifier of the berry under the [Cobblemon.MODID] namespace.
* @return The [Berry] if loaded otherwise null.
*/
@JvmStatic
fun getByName(name: String): Berry? = this.getByIdentifier(cobblemonResource(name))
}
@@ -0,0 +1,29 @@
/*
* 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.berry.spawncondition
import com.cobblemon.mod.common.api.berry.Berry
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.Holder
import net.minecraft.tags.TagKey
import net.minecraft.util.RandomSource
import net.minecraft.world.level.biome.Biome
class SpecificBiomeCondition : BerrySpawnCondition {
lateinit var biome: TagKey<Biome>
val minGroveSize: Int = 1
val maxGroveSize: Int = 1
override fun canSpawn(berry: Berry, biome: Holder<Biome>) = biome.`is`(this.biome)
override fun getGroveSize(random: RandomSource) = random.nextIntBetweenInclusive(minGroveSize, maxGroveSize)
companion object {
val ID = cobblemonResource("specific_biome")
}
}
@@ -8,8 +8,14 @@
package com.cobblemon.mod.common.api.cooking
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.util.math.geometry.toDegrees
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.util.FastColor
import net.minecraft.world.item.ItemStack
import kotlin.math.atan2
import kotlin.math.cos
import kotlin.math.sin
private val colourMap = mapOf(
Flavour.SPICY to 0xFEB37D,
@@ -49,37 +55,111 @@ fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolea
if (colors.isEmpty()) return null
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
acc[0] += FastColor.ARGB32.alpha(color)
acc[1] += FastColor.ARGB32.red(color)
acc[2] += FastColor.ARGB32.green(color)
acc[3] += FastColor.ARGB32.blue(color)
acc
}
return FastColor.ARGB32.color(
alphaSum / colors.size,
redSum / colors.size,
greenSum / colors.size,
blueSum / colors.size
)
return getColourMixFromColors(colors)
}
fun getColourMixFromRideStatBoosts(dominantBoosts: Iterable<RidingStat>, forBubbles: Boolean = false): Int? {
return getColourMixFromFlavours(dominantBoosts.map { it.flavour }, forBubbles)
}
// Mixing RGB colors directly often gives poor results
// Converting them to HSL and averaging hues circularly produces more natural blends
fun getColourMixFromColors(colors: List<Int>): Int? {
if (colors.isEmpty()) return null
if (colors.size == 1) return colors[0]
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
acc[0] += FastColor.ARGB32.alpha(color)
acc[1] += FastColor.ARGB32.red(color)
acc[2] += FastColor.ARGB32.green(color)
acc[3] += FastColor.ARGB32.blue(color)
acc
val hslColors = colors.map {
val red = FastColor.ARGB32.red(it)
val green = FastColor.ARGB32.green(it)
val blue = FastColor.ARGB32.blue(it)
rgbToHsl(red, green, blue)
}
return FastColor.ARGB32.color(
alphaSum / colors.size,
redSum / colors.size,
greenSum / colors.size,
blueSum / colors.size
val hues = hslColors.map { it.h.toDouble() }
val huesAverage = hueAverage(hues).toFloat()
val saturations = hslColors.map { it.s }
val saturationsAverage = average(saturations)
val lightness = hslColors.map { it.l }
val lightnessAverage = average(lightness)
val rgbColor = hslToRgb(huesAverage, saturationsAverage, lightnessAverage)
return FastColor.ARGB32.color(rgbColor.r, rgbColor.g, rgbColor.b)
}
// Based on https://iter.ca/post/hue-avg
fun hueAverage(hues: List<Double>): Float {
val points = hues.map { hue ->
val rad = hue.toRadians()
Pair(cos(rad), sin(rad))
}
val avgX = points.sumOf { it.first.toDouble() } / points.size
val avgY = points.sumOf { it.second.toDouble() } / points.size
var degrees = atan2(avgY, avgX).toDegrees()
if (degrees < 0) {
degrees += 360f
} else if (degrees > 360) {
degrees -= 360f
}
return degrees
}
fun average(values: List<Float>): Float {
if (values.isEmpty()) return 0f
return values.sum() / values.size
}
data class HSL(val h: Float, val s: Float, val l: Float)
fun rgbToHsl(r: Int, g: Int, b: Int): HSL {
val rf = r / 255f
val gf = g / 255f
val bf = b / 255f
val max = maxOf(rf, gf, bf)
val min = minOf(rf, gf, bf)
val delta = max - min
var h = 0f
val l = (max + min) / 2f
val s = if (delta == 0f) 0f else delta / (1f - kotlin.math.abs(2f * l - 1f))
if (delta != 0f) {
h = when (max) {
rf -> ((gf - bf) / delta) % 6f
gf -> ((bf - rf) / delta) + 2f
else -> ((rf - gf) / delta) + 4f
}
h *= 60f
if (h < 0) h += 360f
}
return HSL(h, s, l)
}
data class RGB(val r: Int, val g: Int, val b: Int)
fun hslToRgb(h: Float, s: Float, l: Float): RGB {
val c = (1f - kotlin.math.abs(2f * l - 1f)) * s
val x = c * (1f - kotlin.math.abs((h / 60f) % 2f - 1f))
val m = l - c / 2f
val (rf, gf, bf) = when {
h < 60f -> Triple(c, x, 0f)
h < 120f -> Triple(x, c, 0f)
h < 180f -> Triple(0f, c, x)
h < 240f -> Triple(0f, x, c)
h < 300f -> Triple(x, 0f, c)
else -> Triple(c, 0f, x)
}
return RGB(
((rf + m) * 255).toInt().coerceIn(0, 255),
((gf + m) * 255).toInt().coerceIn(0, 255),
((bf + m) * 255).toInt().coerceIn(0, 255)
)
}
@@ -28,12 +28,14 @@ import net.minecraft.server.level.ServerPlayer
object DialogueManager {
val activeDialogues = mutableMapOf<UUID, ActiveDialogue>()
@JvmStatic
fun startDialogue(playerEntity: ServerPlayer, dialogue: Dialogue): ActiveDialogue {
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
startDialogue(activeDialogue)
return activeDialogue
}
@JvmStatic
fun startDialogue(playerEntity: ServerPlayer, npcEntity: NPCEntity, dialogue: Dialogue): ActiveDialogue {
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
activeDialogue.runtime.withNPCValue("npc", npcEntity)
@@ -42,6 +44,7 @@ object DialogueManager {
return activeDialogue
}
@JvmStatic
fun startDialogue(activeDialogue: ActiveDialogue) {
activeDialogue.initialize()
if (!activeDialogue.completion.isDone) {
@@ -49,6 +52,7 @@ object DialogueManager {
}
}
@JvmStatic
fun stopDialogue(playerEntity: ServerPlayer) {
val activeDialogue = playerEntity.activeDialogue ?: return
DialogueClosedPacket(activeDialogue.dialogueId).sendToPlayer(playerEntity)
@@ -10,14 +10,12 @@ package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import kotlin.random.Random
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
/**
@@ -95,6 +93,16 @@ class DropTable {
pokemon: Pokemon? = null,
) {
val drops = getDrops(amount, pokemon).toMutableList()
postLootDroppedEvent(drops, entity, world, pos, player)
}
fun postLootDroppedEvent(
drops: MutableList<DropEntry>,
entity: LivingEntity?,
world: ServerLevel,
pos: Vec3,
player: ServerPlayer?,
) {
LOOT_DROPPED.postThen(
event = LootDroppedEvent(this, player, entity, drops),
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
@@ -110,4 +118,4 @@ class DropTable {
val entries = buffer.readInt()
repeat(entries) { this.entries.add(ItemDropEntry().decode(buffer)) }
}
}
}
@@ -22,6 +22,7 @@ interface PokemonSideDelegate : EntitySideDelegate<PokemonEntity> {
fun handleStatus(status: Byte) {}
fun spawnShinyParticle(player: Player) {}
fun spawnAspectParticle() {}
fun applyRenderRotation(partialTick: Float) {}
fun positionRider(passenger: Entity, positionUpdater: MoveFunction)
fun updateAge(age: Int) {}
}
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.api.events.berry.BerryHarvestEvent
import com.cobblemon.mod.common.api.events.berry.BerryMutationOfferEvent
import com.cobblemon.mod.common.api.events.berry.BerryMutationResultEvent
import com.cobblemon.mod.common.api.events.berry.BerryYieldCalculationEvent
import com.cobblemon.mod.common.api.events.cooking.PokeSnackSpawnPokemonEvent
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
import com.cobblemon.mod.common.api.events.entity.*
import com.cobblemon.mod.common.api.events.farming.ApricornHarvestEvent
@@ -327,6 +328,12 @@ object CobblemonEvents {
@JvmField
val BOBBER_SPAWN_POKEMON_POST = EventObservable<BobberSpawnPokemonEvent.Post>()
@JvmField
val POKE_SNACK_SPAWN_POKEMON_PRE = CancelableObservable<PokeSnackSpawnPokemonEvent.Pre>()
@JvmField
val POKE_SNACK_SPAWN_POKEMON_POST = EventObservable<PokeSnackSpawnPokemonEvent.Post>()
@JvmField
val BAIT_EFFECT_REGISTRATION = EventObservable<BaitEffectFunctionRegistryEvent>()
@@ -0,0 +1,38 @@
/*
* 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.cooking
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
interface PokeSnackSpawnPokemonEvent {
data class Pre(
val pokeSnackBlockEntity: PokeSnackBlockEntity,
val spawnAction: SpawnAction<*>,
) : Cancelable(), PokeSnackSpawnPokemonEvent {
val context = mapOf<String, MoValue>()
val functions = moLangFunctionMap(
cancelFunc
)
}
data class Post(
val pokeSnackBlockEntity: PokeSnackBlockEntity,
val spawnAction: SpawnAction<*>,
val pokemonEntity: PokemonEntity,
) : PokeSnackSpawnPokemonEvent {
val context = mapOf<String, MoValue>()
}
}
@@ -57,6 +57,7 @@ object PokeRods : JsonDataRegistry<PokeRod> {
* Gets a Pokerod from registry name.
* @return the pokerod object if found otherwise null.
*/
@JvmStatic
fun getPokeRod(name : ResourceLocation): PokeRod? = rods[name]
}
@@ -68,6 +68,7 @@ class SpawnBait(
val TYPING = cobblemonResource("typing")
val EGG_GROUP = cobblemonResource("egg_group")
val SHINY_REROLL = cobblemonResource("shiny_reroll")
val DROPS_REROLL = cobblemonResource("drops_reroll")
val HIDDEN_ABILITY_CHANCE = cobblemonResource("ha_chance")
val POKEMON_CHANCE = cobblemonResource("pokemon_chance")
val FRIENDSHIP = cobblemonResource("friendship")
@@ -85,6 +86,7 @@ class SpawnBait(
registerEffect(NATURE) { entity, effect -> FishingSpawnCause.alterNatureAttempt(entity, effect) }
registerEffect(IV) { entity, effect -> FishingSpawnCause.alterIVAttempt(entity, effect) }
registerEffect(SHINY_REROLL) { entity, effect -> FishingSpawnCause.shinyReroll(entity, effect) }
registerEffect(DROPS_REROLL) { entity, effect -> FishingSpawnCause.saveDropsReroll(entity, effect) }
registerEffect(GENDER_CHANCE) { entity, effect -> FishingSpawnCause.alterGenderAttempt(entity, effect) }
registerEffect(LEVEL_RAISE) { entity, effect -> FishingSpawnCause.alterLevelAttempt(entity, effect) }
registerEffect(HIDDEN_ABILITY_CHANCE) { entity, _ -> FishingSpawnCause.alterHAAttempt(entity) }
@@ -53,20 +53,24 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
}
}
@JvmStatic
fun getEffectsFromRodItemStack(stack: ItemStack): List<SpawnBait.Effect> {
return getEffectsFromItemStack(stack.components.get(CobblemonItemComponents.BAIT)?.stack ?: ItemStack.EMPTY)
}
@JvmStatic
fun getEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
val componentEffects = stack.get(CobblemonItemComponents.BAIT_EFFECTS)?.effects ?: emptyList()
return componentEffects.mapNotNull(::getFromIdentifier).flatMap { it.effects } +
getEffectsFromItem(stack.itemHolder)
}
@JvmStatic
fun getBaitIdentifiersFromItem(holder: Holder<Item>): List<ResourceLocation> {
return effectsMap.entries.filter { it.value.item.fits(holder) }.map { it.key }
}
@JvmStatic
fun getBaitFromItemStack(holder: Holder<Item>): List<SpawnBait> {
return effectsMap.values.filter { it.item.fits(holder) }
}
@@ -75,6 +79,7 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
return getBaitFromItemStack(holder).flatMap { it.effects }
}
@JvmStatic
fun getFromIdentifier(identifier: ResourceLocation): SpawnBait? {
// Check normal spawn bait registry
effectsMap[identifier]?.let { return it }
@@ -98,6 +103,7 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
}
// if it has bait effects and is not listed as a seasoning then it is a bait
@JvmStatic
fun isFishingBait(stack: ItemStack): Boolean {
val holder = stack.itemHolder
return effectsMap.values.any { it.item.fits(holder) }
@@ -11,24 +11,18 @@ package com.cobblemon.mod.common.api.fishing
import kotlin.math.ceil
object SpawnBaitUtils {
@JvmStatic
fun mergeEffects(effects: List<SpawnBait.Effect>): List<SpawnBait.Effect> {
val grouped = effects.groupBy { Pair(it.type, it.subcategory) }
return grouped.map { (key, groupEffects) ->
val (type, subcategory) = key
val count = groupEffects.size
val totalChance = groupEffects.sumOf { it.chance }
val totalValue = groupEffects.sumOf { it.value }
val multiplier = when (count) {
2 -> 0.8
3 -> 0.6
else -> 1.0
}
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
val adjustedValue = ceil(totalValue * multiplier)
val adjustedChance = totalChance.coerceAtMost(1.0)
val adjustedValue = ceil(totalValue)
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
}
@@ -69,6 +69,7 @@ object Fossils: JsonDataRegistry<Fossil> {
/**
* Gets all loaded [Fossil]s.
*/
@JvmStatic
fun all() = this.fossils.values.toList()
/**
@@ -76,6 +77,7 @@ object Fossils: JsonDataRegistry<Fossil> {
* @param identifier The identifier of the fossil.
* @return The [Fossil] if loaded, otherwise null.
*/
@JvmStatic
fun getByIdentifier(identifier: ResourceLocation): Fossil? = this.fossils[identifier]
/**
@@ -83,6 +85,7 @@ object Fossils: JsonDataRegistry<Fossil> {
* @param fossilStacks The fossil [ItemStack]'s.
* @return The [Fossil] if found, otherwise null.
*/
@JvmStatic
fun getFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
return this.all().firstOrNull { it.matchesIngredients(fossilStacks) }
}
@@ -92,6 +95,7 @@ object Fossils: JsonDataRegistry<Fossil> {
* @param fossilStacks The fossil [ItemStack]'s.
* @return The [Fossil] if found to be a superset, otherwise null.
*/
@JvmStatic
fun getSubFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
return this.all().firstOrNull { it.matchesIngredientsSubSet(fossilStacks) }
}
@@ -100,6 +104,7 @@ object Fossils: JsonDataRegistry<Fossil> {
* @param itemStack The ingredient [ItemStack].
* @return true if it's a fossil ingredient, otherwise false.
*/
@JvmStatic
fun isFossilIngredient(itemStack: ItemStack): Boolean {
return this.all().any { it.isIngredient(itemStack) }
}
@@ -57,6 +57,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
}
}
@JvmStatic
fun isNaturalMaterial(item: ItemStack): Boolean {
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
return itemId in itemMap.keys || tagMap.keys.any {
@@ -64,6 +65,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
}
}
@JvmStatic
fun getContent(item: ItemStack): Int? {
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
if (itemId in itemMap.keys) {
@@ -76,6 +78,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
return null
}
@JvmStatic
fun getReturnItem(item: ItemStack): ResourceLocation? {
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
if (itemId in itemMap.keys) {
@@ -87,4 +90,4 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
}
return null
}
}
}
@@ -56,7 +56,9 @@ object Marks: JsonDataRegistry<Mark> {
/**
* Gets all loaded [Mark]s.
*/
@JvmStatic
fun all() = this.marks.values.toList()
@JvmStatic
fun identifiers(): Collection<String> = marks.keys.toSet().map { it.toString() }
/**
@@ -64,5 +66,6 @@ object Marks: JsonDataRegistry<Mark> {
* @param identifier The identifier of the mark.
* @return The [Mark] if loaded, otherwise null.
*/
@JvmStatic
fun getByIdentifier(identifier: ResourceLocation): Mark? = this.marks[identifier]
}
}
@@ -12,7 +12,6 @@ import com.bedrockk.molang.runtime.MoLangEnvironment
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.struct.ArrayStruct
import com.bedrockk.molang.runtime.struct.MoStruct
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.struct.VariableStruct
import com.bedrockk.molang.runtime.value.DoubleValue
@@ -40,7 +39,6 @@ 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.NPCProvider
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
import com.cobblemon.mod.common.api.npc.NPCClass
import com.cobblemon.mod.common.api.npc.NPCClasses
import com.cobblemon.mod.common.api.npc.configuration.interaction.DialogueNPCInteractionConfiguration
import com.cobblemon.mod.common.api.npc.configuration.interaction.ScriptNPCInteractionConfiguration
@@ -57,7 +55,6 @@ import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.experience.SidemodExperienceSource
import com.cobblemon.mod.common.api.pokemon.moves.LearnsetQuery
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.riding.Rideable
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
import com.cobblemon.mod.common.api.scheduling.Schedulable
@@ -137,7 +134,6 @@ import net.minecraft.world.entity.LightningBolt
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.PlayerRideable
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.memory.MemoryModuleType
@@ -145,7 +141,6 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.memory.WalkTarget
import net.minecraft.world.entity.animal.Animal
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.entity.monster.Enemy
import net.minecraft.world.entity.monster.Monster
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
@@ -160,9 +155,6 @@ import net.minecraft.world.level.levelgen.Heightmap
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import kotlin.text.get
import kotlin.text.toInt
import kotlin.toString
/**
* Holds a bunch of useful MoLang trickery that can be used or extended in API
@@ -598,10 +590,10 @@ object MoLangFunctions {
}
if (player is ServerPlayer) {
map.put("seen_credits") { _ ->
DoubleValue( DoubleValue(player.seenCredits) )
DoubleValue(player.seenCredits)
}
map.put("is_in_dialogue") { _ ->
DoubleValue( DoubleValue(player.isInDialogue) )
DoubleValue(player.isInDialogue)
}
map.put("active_dialogue") { _ ->
if (player.isInDialogue) {
@@ -1185,16 +1177,28 @@ object MoLangFunctions {
return@put DoubleValue.ONE
}
map.put("has_memory_value") { params ->
val memoryTypes = params.params.map {
it.asString().asIdentifierDefaultingNamespace()
}.map(BuiltInRegistries.MEMORY_MODULE_TYPE::get)
return@put DoubleValue(memoryTypes.all { entity.brain.checkMemory(it, MemoryStatus.VALUE_PRESENT) })
for (param in params.params) {
if (!entity.hasMemoryFromString(param.asString())) {
return@put DoubleValue.ZERO
}
}
return@put DoubleValue.ONE
}
map.put("lacks_memory_value") { params ->
val memoryTypes = params.params.map {
it.asString().asIdentifierDefaultingNamespace()
}.map(BuiltInRegistries.MEMORY_MODULE_TYPE::get)
return@put DoubleValue(memoryTypes.none { entity.brain.checkMemory(it, MemoryStatus.VALUE_PRESENT) })
for (param in params.params) {
if (entity.hasMemoryFromString(param.asString())) {
return@put DoubleValue.ZERO
}
}
return@put DoubleValue.ONE
}
map.put("is_doing_activity") { params ->
for (param in params.params) {
if (entity.isDoingActivityFromString(param.asString())) {
return@put DoubleValue.ONE
}
}
return@put DoubleValue.ZERO
}
map.put("can_see") { params ->
val target = params.get<MoValue>(0)
@@ -1252,15 +1256,6 @@ object MoLangFunctions {
map.put("in_battle") { DoubleValue(npc.isInBattle()) }
map.put("battles") { ArrayStruct(npc.battleIds.mapNotNull { BattleRegistry.getBattle(it)?.struct }.mapIndexed { index, value -> "$index" to value }.toMap()) }
map.put("stop_battles") { _ -> npc.battleIds.forEach { BattleRegistry.getBattle(it)?.stop() } }
map.put("is_doing_activity") { params ->
val identifiers = params.params.map { it.asString().asIdentifierDefaultingNamespace(namespace = "minecraft") }
val activities = identifiers.mapNotNull { identifier -> BuiltInRegistries.ACTIVITY.get(identifier) }
if (activities.isNotEmpty()) {
return@put DoubleValue(activities.any { activity -> npc.brain.isActive(activity) })
} else {
return@put DoubleValue.ZERO
}
}
map.put("run_script_on_client") { params ->
val world = npc.level()
if (world is ServerLevel) {
@@ -1905,6 +1900,9 @@ object MoLangFunctions {
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).let {
it.isEmpty || it.`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS) || it.`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)
}) }
map.put("riding_style") {
StringValue(pokemonEntity.ifRidingAvailableSupply("") { behaviour, settings, state -> behaviour.getRidingStyle(settings, state).name })
}
map.put("is_wearing_hat") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS)) }
map.put("is_wearing_face") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)) }
map.put("is_pastured") {
@@ -2657,5 +2655,4 @@ object MoLangFunctions {
}
}
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
@@ -9,8 +9,8 @@
package com.cobblemon.mod.common.api.molang
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import net.minecraft.resources.ResourceLocation
@@ -23,11 +23,11 @@ import net.minecraft.resources.ResourceLocation
*/
class ReferenceExpression(val identifier: ResourceLocation) : ExpressionLike {
override fun resolve(runtime: MoLangRuntime, context: Map<String, MoValue>): MoValue {
return getScript()?.resolve(runtime, context) ?: DoubleValue.ZERO
return getScript()?.resolve(runtime, context) ?: StringValue(identifier.toString())
}
override fun toString(): String {
return getScript()?.getString() ?: "0"
return getScript()?.getString() ?: identifier.toString()
}
fun getScript() = CobblemonScripts.scripts[identifier]
@@ -33,6 +33,7 @@ object HiddenPowerUtil {
ElementalTypes.DARK
)
@JvmStatic
fun getHiddenPowerType(pokemon: Pokemon?): ElementalType {
if (pokemon == null) {
return ElementalTypes.NORMAL
@@ -53,8 +53,7 @@ open class MoveTemplate(
val pp: Int,
val priority: Int,
val critRatio: Double,
val effectChances: Array<Double>,
val actionEffect: ActionEffectTimeline?
val effectChances: Array<Double>
) {
val struct: MoStruct by lazy {
QueryStruct(hashMapOf())
@@ -87,8 +86,7 @@ open class MoveTemplate(
pp = 5,
priority = 0,
critRatio = 0.0,
effectChances = emptyArray(),
actionEffect = null
effectChances = emptyArray()
)
companion object {
@@ -92,18 +92,7 @@ object Moves : DataRegistry {
effectChances += secondaryMember.get("chance").asDouble
}
}
val actionEffect = ActionEffects.actionEffects[id.asIdentifierDefaultingNamespace()]
?: run {
ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
// if (damageCategory == DamageCategories.STATUS) {
// ActionEffects.actionEffects[cobblemonResource("status")]
// } else {
// val type = elementalType.name.lowercase()
// val category = damageCategory.name.lowercase()
// ActionEffects.actionEffects["${category}_$type".asIdentifierDefaultingNamespace()]
// }
}
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray(), actionEffect)
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray())
this.register(move)
} catch (e: Exception) {
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
@@ -117,12 +106,19 @@ object Moves : DataRegistry {
MovesRegistrySyncPacket(all()).sendToPlayer(player)
}
@JvmStatic
fun getByName(name: String) = allMoves[name.lowercase()]
@JvmStatic
fun getByNumericalId(id: Int) = idMapping[id]
@JvmStatic
fun getByNameOrDummy(name: String) = allMoves[name.lowercase()] ?: MoveTemplate.dummy(name.lowercase())
@JvmStatic
fun getExceptional() = getByName("tackle") ?: allMoves.values.random()
@JvmStatic
fun count() = allMoves.size
@JvmStatic
fun names(): Collection<String> = this.allMoves.keys.toSet()
@JvmStatic
fun all() = this.allMoves.values.toList()
internal fun receiveSyncPacket(moves: Collection<MoveTemplate>) {
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.keyframes.*
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.pokemon.adapters.CobblemonStatTypeAdapter
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
@@ -91,5 +92,11 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
observable.emit(this)
}
fun getEffectWithBattleContext(id: ResourceLocation, pokemon: BattlePokemon): ActionEffectTimeline? {
val species = pokemon.entity?.exposedSpecies ?: pokemon.effectedPokemon.species
val contextedEffect = actionEffects[ResourceLocation.fromNamespaceAndPath(id.namespace, id.path + "_" + species)]
return contextedEffect ?: actionEffects[id]
}
override fun sync(player: ServerPlayer) {}
}
@@ -97,6 +97,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
override val observable = SimpleObservable<NPCClasses>()
private val npcClassesByIdentifier = hashMapOf<ResourceLocation, NPCClass>()
@JvmStatic
val classes: Collection<NPCClass>
get() = this.npcClassesByIdentifier.values
@@ -116,6 +117,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
* @param identifier The unique [NPCClass.id] of the [NPCClass].
* @return The [NPCClass] if existing.
*/
@JvmStatic
fun getByIdentifier(identifier: ResourceLocation) = this.npcClassesByIdentifier[identifier]
/**
@@ -123,6 +125,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
*
* @return The loaded NPC class amount.
*/
@JvmStatic
fun count() = this.npcClassesByIdentifier.size
/**
@@ -132,6 +135,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
*
* @return A randomly selected [Species].
*/
@JvmStatic
fun random(): NPCClass = this.npcClassesByIdentifier.values.random()
fun dummy(): NPCClass {
@@ -102,6 +102,7 @@ object NPCPresets : JsonDataRegistry<NPCPreset> {
observable.emit(this)
}
@JvmStatic
fun getPreset(identifier: ResourceLocation): NPCPreset? {
return npcPresetsByIdentifier[identifier]
}
@@ -63,7 +63,7 @@ open class OrientationController(val entity: LivingEntity) {
}
fun getRenderOrientation(delta: Float): Quaternionf {
val old = renderOrientationO ?: renderOrientation ?: orientation
val old = renderOrientationO ?: renderOrientation ?: orientation ?: Matrix3f()
val new = renderOrientation ?: old
val oldQuat = Quaternionf().setFromUnnormalized(old)
val newQuat = Quaternionf().setFromUnnormalized(new)
@@ -23,11 +23,14 @@ object PastureLinkManager {
// Maps player UUID
val links = mutableMapOf<UUID, PastureLink>()
@JvmStatic
fun getLinkByPlayerId(playerId: UUID) = links[playerId]
@JvmStatic
fun createLink(playerId: UUID, link: PastureLink) {
links[playerId] = link
}
@JvmStatic
fun getLinkByPlayer(player: ServerPlayer): PastureLink? {
val link = getLinkByPlayerId(player.uuid)
if (link != null) {
@@ -40,6 +43,7 @@ object PastureLinkManager {
return link
}
@JvmStatic
fun removeAt(world: ServerLevel, pos: BlockPos) {
links.removeIf { (uuid, pastureLink) ->
val shouldRemove = world.dimensionTypeRegistration().`is`(pastureLink.dimension) && pastureLink.pos == pos
@@ -28,6 +28,7 @@ import net.minecraft.server.level.ServerPlayer
object PasturePermissionControllers {
val controllers = PrioritizedList<PasturePermissionController>()
@JvmStatic
fun permit(player: ServerPlayer, pastureBlockEntity: PokemonPastureBlockEntity): PasturePermissions {
return controllers.firstNotNullOfOrNull { it.permit(player, pastureBlockEntity) }
?: PasturePermissions(
@@ -147,6 +147,7 @@ object CobblemonPermissions {
@JvmStatic
val SEE_HIDDEN_NPCS = this.create("seehiddennpcs", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@JvmStatic
fun all(): Iterable<Permission> = this.permissions
private fun create(node: String, level: PermissionLevel): Permission {
@@ -53,100 +53,196 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
// ToDo datapack pokeball type here instead
private val custom = hashMapOf<ResourceLocation, PokeBall>()
@JvmStatic
@get:JvmName("getPokeBall")
val POKE_BALL
get() = this.byName("poke_ball")
@JvmStatic
@get:JvmName("getSlateBall")
val SLATE_BALL
get() = this.byName("slate_ball")
@JvmStatic
@get:JvmName("getAzureBall")
val AZURE_BALL
get() = this.byName("azure_ball")
@JvmStatic
@get:JvmName("getVerdantBall")
val VERDANT_BALL
get() = this.byName("verdant_ball")
@JvmStatic
@get:JvmName("getRoseateBall")
val ROSEATE_BALL
get() = this.byName("roseate_ball")
@JvmStatic
@get:JvmName("getCitrineBall")
val CITRINE_BALL
get() = this.byName("citrine_ball")
@JvmStatic
@get:JvmName("getGreatBall")
val GREAT_BALL
get() = this.byName("great_ball")
@JvmStatic
@get:JvmName("getUltraBall")
val ULTRA_BALL
get() = this.byName("ultra_ball")
@JvmStatic
@get:JvmName("getMasterBall")
val MASTER_BALL
get() = this.byName("master_ball")
@JvmStatic
@get:JvmName("getSafariBall")
val SAFARI_BALL
get() = this.byName("safari_ball")
@JvmStatic
@get:JvmName("getFastBall")
val FAST_BALL
get() = this.byName("fast_ball")
@JvmStatic
@get:JvmName("getLevelBall")
val LEVEL_BALL
get() = this.byName("level_ball")
@JvmStatic
@get:JvmName("getLureBall")
val LURE_BALL
get() = this.byName("lure_ball")
@JvmStatic
@get:JvmName("getHeavyBall")
val HEAVY_BALL
get() = this.byName("heavy_ball")
@JvmStatic
@get:JvmName("getLoveBall")
val LOVE_BALL
get() = this.byName("love_ball")
@JvmStatic
@get:JvmName("getFriendBall")
val FRIEND_BALL
get() = this.byName("friend_ball")
@JvmStatic
@get:JvmName("getMoonBall")
val MOON_BALL
get() = this.byName("moon_ball")
@JvmStatic
@get:JvmName("getSportBall")
val SPORT_BALL
get() = this.byName("sport_ball")
@JvmStatic
@get:JvmName("getNetBall")
val NET_BALL
get() = this.byName("net_ball")
@JvmStatic
@get:JvmName("getDiveBall")
val DIVE_BALL
get() = this.byName("dive_ball")
@JvmStatic
@get:JvmName("getNestBall")
val NEST_BALL
get() = this.byName("nest_ball")
@JvmStatic
@get:JvmName("getRepeatBall")
val REPEAT_BALL
get() = this.byName("repeat_ball")
@JvmStatic
@get:JvmName("getTimerBall")
val TIMER_BALL
get() = this.byName("timer_ball")
@JvmStatic
@get:JvmName("getLuxuryBall")
val LUXURY_BALL
get() = this.byName("luxury_ball")
@JvmStatic
@get:JvmName("getPremierBall")
val PREMIER_BALL
get() = this.byName("premier_ball")
@JvmStatic
@get:JvmName("getDuskBall")
val DUSK_BALL
get() = this.byName("dusk_ball")
@JvmStatic
@get:JvmName("getHealBall")
val HEAL_BALL
get() = this.byName("heal_ball")
@JvmStatic
@get:JvmName("getQuickBall")
val QUICK_BALL
get() = this.byName("quick_ball")
@JvmStatic
@get:JvmName("getCherishBall")
val CHERISH_BALL
get() = this.byName("cherish_ball")
@JvmStatic
@get:JvmName("getParkBall")
val PARK_BALL
get() = this.byName("park_ball")
@JvmStatic
@get:JvmName("getDreamBall")
val DREAM_BALL
get() = this.byName("dream_ball")
@JvmStatic
@get:JvmName("getBeastBall")
val BEAST_BALL
get() = this.byName("beast_ball")
@JvmStatic
@get:JvmName("getAncientPokeBall")
val ANCIENT_POKE_BALL
get() = this.byName("ancient_poke_ball")
@JvmStatic
@get:JvmName("getAncientCitrineBall")
val ANCIENT_CITRINE_BALL
get() = this.byName("ancient_citrine_ball")
@JvmStatic
@get:JvmName("getAncientVerdantBall")
val ANCIENT_VERDANT_BALL
get() = this.byName("ancient_verdant_ball")
@JvmStatic
@get:JvmName("getAncientAzureBall")
val ANCIENT_AZURE_BALL
get() = this.byName("ancient_azure_ball")
@JvmStatic
@get:JvmName("getAncientRoseateBall")
val ANCIENT_ROSEATE_BALL
get() = this.byName("ancient_roseate_ball")
@JvmStatic
@get:JvmName("getAncientSlateBall")
val ANCIENT_SLATE_BALL
get() = this.byName("ancient_slate_ball")
@JvmStatic
@get:JvmName("getAncientIvoryBall")
val ANCIENT_IVORY_BALL
get() = this.byName("ancient_ivory_ball")
@JvmStatic
@get:JvmName("getAncientGreatBall")
val ANCIENT_GREAT_BALL
get() = this.byName("ancient_great_ball")
@JvmStatic
@get:JvmName("getAncientUltraBall")
val ANCIENT_ULTRA_BALL
get() = this.byName("ancient_ultra_ball")
@JvmStatic
@get:JvmName("getAncientHeavyBall")
val ANCIENT_HEAVY_BALL
get() = this.byName("ancient_heavy_ball")
@JvmStatic
@get:JvmName("getAncientLeadenBall")
val ANCIENT_LEADEN_BALL
get() = this.byName("ancient_leaden_ball")
@JvmStatic
@get:JvmName("getAncientGigatonBall")
val ANCIENT_GIGATON_BALL
get() = this.byName("ancient_gigaton_ball")
@JvmStatic
@get:JvmName("getAncientFeatherBall")
val ANCIENT_FEATHER_BALL
get() = this.byName("ancient_feather_ball")
@JvmStatic
@get:JvmName("getAncientWingBall")
val ANCIENT_WING_BALL
get() = this.byName("ancient_wing_ball")
@JvmStatic
@get:JvmName("getAncientJetBall")
val ANCIENT_JET_BALL
get() = this.byName("ancient_jet_ball")
@JvmStatic
@get:JvmName("getAncientOriginBall")
val ANCIENT_ORIGIN_BALL
get() = this.byName("ancient_origin_ball")
@@ -225,8 +321,10 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
* Gets a Pokeball from registry name.
* @return the pokeball object if found otherwise null.
*/
@JvmStatic
fun getPokeBall(name : ResourceLocation): PokeBall? = this.custom[name] ?: this.defaults[name]
@JvmStatic
fun all() = this.defaults.filterKeys { !this.custom.containsKey(it) }.values + this.custom.values
private fun createDefault(
@@ -250,4 +348,196 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
val identifier = cobblemonResource(name)
return this.custom[identifier] ?: this.defaults[identifier]!!
}
/**
* Backwards compatibility getters
*/
@JvmName("getPOKE_BALL")
@Deprecated("Use PokeBalls.getPokeBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getPOKE_BALL() = POKE_BALL
@JvmName("getSLATE_BALL")
@Deprecated("Use PokeBalls.getSlateBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getSLATE_BALL() = SLATE_BALL
@JvmName("getAZURE_BALL")
@Deprecated("Use PokeBalls.getAzureBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getAZURE_BALL() = AZURE_BALL
@JvmName("getVERDANT_BALL")
@Deprecated("Use PokeBalls.getVerdantBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getVERDANT_BALL() = VERDANT_BALL
@JvmName("getROSEATE_BALL")
@Deprecated("Use PokeBalls.getRoseateBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getROSEATE_BALL() = ROSEATE_BALL
@JvmName("getCITRINE_BALL")
@Deprecated("Use PokeBalls.getCitrineBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getCITRINE_BALL() = CITRINE_BALL
@JvmName("getGREAT_BALL")
@Deprecated("Use PokeBalls.getGreatBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getGREAT_BALL() = GREAT_BALL
@JvmName("getULTRA_BALL")
@Deprecated("Use PokeBalls.getUltraBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getULTRA_BALL() = ULTRA_BALL
@JvmName("getMASTER_BALL")
@Deprecated("Use PokeBalls.getMasterBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getMASTER_BALL() = MASTER_BALL
@JvmName("getSAFARI_BALL")
@Deprecated("Use PokeBalls.getSafariBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getSAFARI_BALL() = SAFARI_BALL
@JvmName("getFAST_BALL")
@Deprecated("Use PokeBalls.getFastBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getFAST_BALL() = FAST_BALL
@JvmName("getLEVEL_BALL")
@Deprecated("Use PokeBalls.getLevelBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getLEVEL_BALL() = LEVEL_BALL
@JvmName("getLURE_BALL")
@Deprecated("Use PokeBalls.getLureBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getLURE_BALL() = LURE_BALL
@JvmName("getHEAVY_BALL")
@Deprecated("Use PokeBalls.getHeavyBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getHEAVY_BALL() = HEAVY_BALL
@JvmName("getLOVE_BALL")
@Deprecated("Use PokeBalls.getLoveBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getLOVE_BALL() = LOVE_BALL
@JvmName("getFRIEND_BALL")
@Deprecated("Use PokeBalls.getFriendBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getFRIEND_BALL() = FRIEND_BALL
@JvmName("getMOON_BALL")
@Deprecated("Use PokeBalls.getMoonBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getMOON_BALL() = MOON_BALL
@JvmName("getSPORT_BALL")
@Deprecated("Use PokeBalls.getSportBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getSPORT_BALL() = SPORT_BALL
@JvmName("getNET_BALL")
@Deprecated("Use PokeBalls.getNetBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getNET_BALL() = NET_BALL
@JvmName("getNEST_BALL")
@Deprecated("Use PokeBalls.getNestBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getNEST_BALL() = NEST_BALL
@JvmName("getREPEAT_BALL")
@Deprecated("Use PokeBalls.getRepeatBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getREPEAT_BALL() = REPEAT_BALL
@JvmName("getTIMER_BALL")
@Deprecated("Use PokeBalls.getTimerBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getTIMER_BALL() = TIMER_BALL
@JvmName("getLUXURY_BALL")
@Deprecated("Use PokeBalls.getLuxuryBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getLUXURY_BALL() = LUXURY_BALL
@JvmName("getPREMIER_BALL")
@Deprecated("Use PokeBalls.getPremierBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getPREMIER_BALL() = PREMIER_BALL
@JvmName("getDUSK_BALL")
@Deprecated("Use PokeBalls.getDuskBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getDUSK_BALL() = DUSK_BALL
@JvmName("getHEAL_BALL")
@Deprecated("Use PokeBalls.getHealBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getHEAL_BALL() = HEAL_BALL
@JvmName("getQUICK_BALL")
@Deprecated("Use PokeBalls.getQuickBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getQUICK_BALL() = QUICK_BALL
@JvmName("getCHERISH_BALL")
@Deprecated("Use PokeBalls.getCherishBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getCHERISH_BALL() = CHERISH_BALL
@JvmName("getPARK_BALL")
@Deprecated("Use PokeBalls.getParkBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getPARK_BALL() = PARK_BALL
@JvmName("getDREAM_BALL")
@Deprecated("Use PokeBalls.getDreamBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getDREAM_BALL() = DREAM_BALL
@JvmName("getBEAST_BALL")
@Deprecated("Use PokeBalls.getBeastBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getBEAST_BALL() = BEAST_BALL
@JvmName("getANCIENT_POKE_BALL")
@Deprecated("Use PokeBalls.getAncientPokeBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_POKE_BALL() = ANCIENT_POKE_BALL
@JvmName("getANCIENT_CITRINE_BALL")
@Deprecated("Use PokeBalls.getAncientCitrineBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_CITRINE_BALL() = ANCIENT_CITRINE_BALL
@JvmName("getANCIENT_VERDANT_BALL")
@Deprecated("Use PokeBalls.getAncientVerdantBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_VERDANT_BALL() = ANCIENT_VERDANT_BALL
@JvmName("getANCIENT_AZURE_BALL")
@Deprecated("Use PokeBalls.getAncientAzureBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_AZURE_BALL() = ANCIENT_AZURE_BALL
@JvmName("getANCIENT_ROSEATE_BALL")
@Deprecated("Use PokeBalls.getAncientRoseateBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_ROSEATE_BALL() = ANCIENT_ROSEATE_BALL
@JvmName("getANCIENT_SLATE_BALL")
@Deprecated("Use PokeBalls.getAncientSlateBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_SLATE_BALL() = ANCIENT_SLATE_BALL
@JvmName("getANCIENT_IVORY_BALL")
@Deprecated("Use PokeBalls.getAncientIvoryBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_IVORY_BALL() = ANCIENT_IVORY_BALL
@JvmName("getANCIENT_GREAT_BALL")
@Deprecated("Use PokeBalls.getAncientGreatBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_GREAT_BALL() = ANCIENT_GREAT_BALL
@JvmName("getANCIENT_ULTRA_BALL")
@Deprecated("Use PokeBalls.getAncientUltraBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_ULTRA_BALL() = ANCIENT_ULTRA_BALL
@JvmName("getANCIENT_HEAVY_BALL")
@Deprecated("Use PokeBalls.getAncientHeavyBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_HEAVY_BALL() = ANCIENT_HEAVY_BALL
@JvmName("getANCIENT_LEADEN_BALL")
@Deprecated("Use PokeBalls.getAncientLeadenBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_LEADEN_BALL() = ANCIENT_LEADEN_BALL
@JvmName("getANCIENT_GIGATON_BALL")
@Deprecated("Use PokeBalls.getAncientGigatonBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_GIGATON_BALL() = ANCIENT_GIGATON_BALL
@JvmName("getANCIENT_FEATHER_BALL")
@Deprecated("Use PokeBalls.getAncientFeatherBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_FEATHER_BALL() = ANCIENT_FEATHER_BALL
@JvmName("getANCIENT_WING_BALL")
@Deprecated("Use PokeBalls.getAncientWingBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_WING_BALL() = ANCIENT_WING_BALL
@JvmName("getANCIENT_JET_BALL")
@Deprecated("Use PokeBalls.getAncientJetBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_JET_BALL() = ANCIENT_JET_BALL
@JvmName("getANCIENT_ORIGIN_BALL")
@Deprecated("Use PokeBalls.getAncientOriginBall(), provided for backwards compatibility until Cobblemon 1.8.")
fun getANCIENT_ORIGIN_BALL() = ANCIENT_ORIGIN_BALL
}
@@ -24,126 +24,151 @@ import net.minecraft.resources.ResourceLocation
object Natures {
private val allNatures = mutableListOf<Nature>()
@JvmField
val HARDY = registerNature(
Nature(cobblemonResource("hardy"), "cobblemon.nature.hardy",
null, null, null, null)
)
@JvmField
val LONELY = registerNature(
Nature(cobblemonResource("lonely"), "cobblemon.nature.lonely",
Stats.ATTACK, Stats.DEFENCE, Flavour.SPICY, Flavour.SOUR)
)
@JvmField
val BRAVE = registerNature(
Nature(cobblemonResource("brave"), "cobblemon.nature.brave",
Stats.ATTACK, Stats.SPEED, Flavour.SPICY, Flavour.SWEET)
)
@JvmField
val ADAMANT = registerNature(
Nature(cobblemonResource("adamant"), "cobblemon.nature.adamant",
Stats.ATTACK, Stats.SPECIAL_ATTACK, Flavour.SPICY, Flavour.DRY)
)
@JvmField
val NAUGHTY = registerNature(
Nature(cobblemonResource("naughty"), "cobblemon.nature.naughty",
Stats.ATTACK, Stats.SPECIAL_DEFENCE, Flavour.SPICY, Flavour.BITTER)
)
@JvmField
val BOLD = registerNature(
Nature(cobblemonResource("bold"), "cobblemon.nature.bold",
Stats.DEFENCE, Stats.ATTACK, Flavour.SOUR, Flavour.SPICY)
)
@JvmField
val DOCILE = registerNature(
Nature(cobblemonResource("docile"), "cobblemon.nature.docile",
null, null, null, null)
)
@JvmField
val RELAXED = registerNature(
Nature(cobblemonResource("relaxed"), "cobblemon.nature.relaxed",
Stats.DEFENCE, Stats.SPEED, Flavour.SOUR, Flavour.SWEET)
)
@JvmField
val IMPISH = registerNature(
Nature(cobblemonResource("impish"), "cobblemon.nature.impish",
Stats.DEFENCE, Stats.SPECIAL_ATTACK, Flavour.SOUR, Flavour.DRY)
)
@JvmField
val LAX = registerNature(
Nature(cobblemonResource("lax"), "cobblemon.nature.lax",
Stats.DEFENCE, Stats.SPECIAL_DEFENCE, Flavour.SOUR, Flavour.BITTER)
)
@JvmField
val TIMID = registerNature(
Nature(cobblemonResource("timid"), "cobblemon.nature.timid",
Stats.SPEED, Stats.ATTACK, Flavour.SWEET, Flavour.SPICY)
)
@JvmField
val HASTY = registerNature(
Nature(cobblemonResource("hasty"), "cobblemon.nature.hasty",
Stats.SPEED, Stats.DEFENCE, Flavour.SWEET, Flavour.SOUR)
)
@JvmField
val SERIOUS = registerNature(
Nature(cobblemonResource("serious"), "cobblemon.nature.serious",
null, null, null, null)
)
@JvmField
val JOLLY = registerNature(
Nature(cobblemonResource("jolly"), "cobblemon.nature.jolly",
Stats.SPEED, Stats.SPECIAL_ATTACK, Flavour.SWEET, Flavour.DRY)
)
@JvmField
val NAIVE = registerNature(
Nature(cobblemonResource("naive"), "cobblemon.nature.naive",
Stats.SPEED, Stats.SPECIAL_DEFENCE, Flavour.SWEET, Flavour.BITTER)
)
@JvmField
val MODEST = registerNature(
Nature(cobblemonResource("modest"), "cobblemon.nature.modest",
Stats.SPECIAL_ATTACK, Stats.ATTACK, null, null)
)
@JvmField
val MILD = registerNature(
Nature(cobblemonResource("mild"), "cobblemon.nature.mild",
Stats.SPECIAL_ATTACK, Stats.DEFENCE, Flavour.DRY, Flavour.SOUR)
)
@JvmField
val QUIET = registerNature(
Nature(cobblemonResource("quiet"), "cobblemon.nature.quiet",
Stats.SPECIAL_ATTACK, Stats.SPEED, Flavour.DRY, Flavour.SWEET)
)
@JvmField
val BASHFUL = registerNature(
Nature(cobblemonResource("bashful"), "cobblemon.nature.bashful",
null, null, null, null)
)
@JvmField
val RASH = registerNature(
Nature(cobblemonResource("rash"), "cobblemon.nature.rash",
Stats.SPECIAL_ATTACK, Stats.SPECIAL_DEFENCE, Flavour.DRY, Flavour.BITTER)
)
@JvmField
val CALM = registerNature(
Nature(cobblemonResource("calm"), "cobblemon.nature.calm",
Stats.SPECIAL_DEFENCE, Stats.ATTACK, Flavour.BITTER, Flavour.SPICY)
)
@JvmField
val GENTLE = registerNature(
Nature(cobblemonResource("gentle"), "cobblemon.nature.gentle",
Stats.SPECIAL_DEFENCE, Stats.DEFENCE, Flavour.BITTER, Flavour.SOUR)
)
@JvmField
val SASSY = registerNature(
Nature(cobblemonResource("sassy"), "cobblemon.nature.sassy",
Stats.SPECIAL_DEFENCE, Stats.SPEED, Flavour.BITTER, Flavour.SWEET)
)
@JvmField
val CAREFUL = registerNature(
Nature(cobblemonResource("careful"), "cobblemon.nature.careful",
Stats.SPECIAL_DEFENCE, Stats.SPECIAL_ATTACK, Flavour.BITTER, Flavour.DRY)
)
@JvmField
val QUIRKY = registerNature(
Nature(cobblemonResource("quirky"), "cobblemon.nature.quirky",
null, null, null, null)
@@ -153,6 +178,7 @@ object Natures {
/**
* Registers a new nature type
*/
@JvmStatic
fun registerNature(nature: Nature): Nature {
allNatures.add(nature)
return nature
@@ -162,6 +188,7 @@ object Natures {
* Gets a nature by registry name
* @return a nature type or null
*/
@JvmStatic
fun getNature(name: ResourceLocation): Nature? {
return allNatures.find { nature -> nature.name == name }
}
@@ -170,20 +197,122 @@ object Natures {
* Utility method to get a nature by string
* @return a nature type or null
*/
fun getNature(identifier: String): Nature? {
val nature = getNature(cobblemonResource(identifier))
if(nature != null) return nature
return getNature(ResourceLocation.parse(identifier))
}
@JvmStatic
fun getNature(identifier: String) = getNature(cobblemonResource(identifier))
?: getNature(ResourceLocation.parse(identifier))
/**
* Helper function for a random Nature
* @return a random nature type
*/
@JvmStatic
fun getRandomNature(): Nature {
return allNatures.random()
}
@JvmStatic
fun all(): Collection<Nature> = this.allNatures.toList()
/**
* Backwards compatibility getters
*/
@JvmName("getHARDY")
@Deprecated("Use Natures.HARDY, provided for backwards compatibility until Cobblemon 1.8.")
fun getHARDY() = HARDY
@JvmName("getLONELY")
@Deprecated("Use Natures.LONELY, provided for backwards compatibility until Cobblemon 1.8.")
fun getLONELY() = LONELY
@JvmName("getBRAVE")
@Deprecated("Use Natures.BRAVE, provided for backwards compatibility until Cobblemon 1.8.")
fun getBRAVE() = BRAVE
@JvmName("getADAMANT")
@Deprecated("Use Natures.ADAMANT, provided for backwards compatibility until Cobblemon 1.8.")
fun getADAMANT() = ADAMANT
@JvmName("getNAUGHTY")
@Deprecated("Use Natures.NAUGHTY, provided for backwards compatibility until Cobblemon 1.8.")
fun getNAUGHTY() = NAUGHTY
@JvmName("getBOLD")
@Deprecated("Use Natures.BOLD, provided for backwards compatibility until Cobblemon 1.8.")
fun getBOLD() = BOLD
@JvmName("getDOCILE")
@Deprecated("Use Natures.DOCILE, provided for backwards compatibility until Cobblemon 1.8.")
fun getDOCILE() = DOCILE
@JvmName("getRELAXED")
@Deprecated("Use Natures.RELAXED, provided for backwards compatibility until Cobblemon 1.8.")
fun getRELAXED() = RELAXED
@JvmName("getIMPISH")
@Deprecated("Use Natures.IMPISH, provided for backwards compatibility until Cobblemon 1.8.")
fun getIMPISH() = IMPISH
@JvmName("getLAX")
@Deprecated("Use Natures.LAX, provided for backwards compatibility until Cobblemon 1.8.")
fun getLAX() = LAX
@JvmName("getTIMID")
@Deprecated("Use Natures.TIMID, provided for backwards compatibility until Cobblemon 1.8.")
fun getTIMID() = TIMID
@JvmName("getHASTY")
@Deprecated("Use Natures.HASTY, provided for backwards compatibility until Cobblemon 1.8.")
fun getHASTY() = HASTY
@JvmName("getSERIOUS")
@Deprecated("Use Natures.SERIOUS, provided for backwards compatibility until Cobblemon 1.8.")
fun getSERIOUS() = SERIOUS
@JvmName("getJOLLY")
@Deprecated("Use Natures.JOLLY, provided for backwards compatibility until Cobblemon 1.8.")
fun getJOLLY() = JOLLY
@JvmName("getNAIVE")
@Deprecated("Use Natures.NAIVE, provided for backwards compatibility until Cobblemon 1.8.")
fun getNAIVE() = NAIVE
@JvmName("getMODEST")
@Deprecated("Use Natures.MODEST, provided for backwards compatibility until Cobblemon 1.8.")
fun getMODEST() = MODEST
@JvmName("getMILD")
@Deprecated("Use Natures.MILD, provided for backwards compatibility until Cobblemon 1.8.")
fun getMILD() = MILD
@JvmName("getQUIET")
@Deprecated("Use Natures.QUIET, provided for backwards compatibility until Cobblemon 1.8.")
fun getQUIET() = QUIET
@JvmName("getBASHFUL")
@Deprecated("Use Natures.BASHFUL, provided for backwards compatibility until Cobblemon 1.8.")
fun getBASHFUL() = BASHFUL
@JvmName("getRASH")
@Deprecated("Use Natures.RASH, provided for backwards compatibility until Cobblemon 1.8.")
fun getRASH() = RASH
@JvmName("getCALM")
@Deprecated("Use Natures.CALM, provided for backwards compatibility until Cobblemon 1.8.")
fun getCALM() = CALM
@JvmName("getGENTLE")
@Deprecated("Use Natures.GENTLE, provided for backwards compatibility until Cobblemon 1.8.")
fun getGENTLE() = GENTLE
@JvmName("getSASSY")
@Deprecated("Use Natures.SASSY, provided for backwards compatibility until Cobblemon 1.8.")
fun getSASSY() = SASSY
@JvmName("getCAREFUL")
@Deprecated("Use Natures.CAREFUL, provided for backwards compatibility until Cobblemon 1.8.")
fun getCAREFUL() = CAREFUL
@JvmName("getQUIRKY")
@Deprecated("Use Natures.QUIRKY, provided for backwards compatibility until Cobblemon 1.8.")
fun getQUIRKY() = QUIRKY
}
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.events.pokemon.ShinyChanceCalculationEvent
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
@@ -31,10 +32,12 @@ import com.cobblemon.mod.common.pokemon.IVs
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.isDouble
import com.cobblemon.mod.common.util.isFloat
import com.cobblemon.mod.common.util.isUuid
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.util.simplify
@@ -146,6 +149,8 @@ open class PokemonProperties {
props.originalTrainer = parsePlayerProperty(keyPairs, listOf("originaltrainer", "ot"))
props.moves = parseString(keyPairs, listOf("moves"))?.split(",")
props.heldItem = parseString(keyPairs, listOf("helditem", "held_item"))
props.minPerfectIVs = parseIntProperty(keyPairs, listOf("min_perfect_ivs"))?.coerceIn(0, Stats.PERMANENT.size)
props.scaleModifier = parseFloatProperty(keyPairs, listOf("scale_modifier"))
val maybeIVs = IVs()
val maybeEVs = EVs()
@@ -195,6 +200,16 @@ open class PokemonProperties {
}
}
private fun parseFloatProperty(keyPairs: MutableList<Pair<String, String?>>, labels: Iterable<String>): Float? {
val matchingKeyPair = getMatchedKeyPair(keyPairs, labels) ?: return null
val value = matchingKeyPair.second
return if (value == null || !value.isFloat()) {
null
} else {
value.toFloat()
}
}
private fun parseIdentifierOfRegistry(keyPairs: MutableList<Pair<String, String?>>, validKeys: List<String>, valueFetcher: (ResourceLocation) -> String?): String? {
val matched = getMatchedKeyPair(keyPairs, validKeys) ?: return null
val value = matched.second?.lowercase() ?: return null
@@ -343,7 +358,9 @@ open class PokemonProperties {
var moves: List<String>? = null
var heldItem: String? = null
var cosmeticItem: String? = null
var scaleModifier: Float? = null
var minPerfectIVs: Int? = null
var ivs: IVs? = null
var evs: EVs? = null
var customProperties = mutableListOf<CustomPokemonProperty>()
@@ -413,6 +430,11 @@ open class PokemonProperties {
pokemon.hyperTrainIV(stat.key, stat.value)
}
}
minPerfectIVs?.let {
CobblemonStatProvider.ofType(Stat.Type.PERMANENT).shuffled().take(it).forEach { stat ->
pokemon.setIV(stat, IVs.MAX_VALUE)
}
}
evs?.let { evs ->
evs.forEach { stat ->
pokemon.setEV(stat.key, stat.value)
@@ -469,6 +491,7 @@ open class PokemonProperties {
if (stack.isEmpty) return@let
pokemon.swapHeldItem(stack, decrement = true, aiCanDrop = false)
}
scaleModifier?.let { pokemon.scaleModifier = it }
pokemon.updateAspects()
}
@@ -512,6 +535,7 @@ open class PokemonProperties {
nature?.takeIf { it != pokemon.nature.name.toString() }?.let { return false }
ability?.takeIf { it != pokemon.ability.name }?.let { return false }
status?.takeIf { it != pokemon.status?.status?.showdownName }?.let { return false }
minPerfectIVs?.takeIf { pokemon.ivs.count { stat -> stat.value == IVs.MAX_VALUE } < it }?.let { return false }
ivs?.forEach{ stat ->
if (stat.value != pokemon.ivs[stat.key]) { return false }
}
@@ -542,6 +566,7 @@ open class PokemonProperties {
return@takeIf false
}?.let { return false }
scaleModifier?.takeIf { it != pokemon.scaleModifier }?.let { return false }
return true
}
@@ -570,6 +595,7 @@ open class PokemonProperties {
nature?.takeIf { it != properties.nature }?.let { return false }
ability?.takeIf { it != properties.ability }?.let { return false }
status?.takeIf { it != properties.status }?.let { return false }
minPerfectIVs?.takeIf { it != properties.minPerfectIVs }?.let { return false }
ivs?.let{ ivs ->
ivs.forEach{ stat ->
//If the potential subset has IV and the main set does not then it cant be a subset
@@ -593,6 +619,7 @@ open class PokemonProperties {
originalTrainerType?.takeIf { it != properties.originalTrainerType }?.let{ return false }
moves?.takeIf { it.any { move -> properties.moves?.none { it == move } == true } }?.let { return false }
fullness?.takeIf { it != properties.fullness }?.let { return false }
scaleModifier?.takeIf { it != properties.scaleModifier }?.let { return false }
return true
}
@@ -646,6 +673,7 @@ open class PokemonProperties {
nature?.let { nbt.putString(DataKeys.POKEMON_NATURE, it) }
ability?.let { nbt.putString(DataKeys.POKEMON_ABILITY, it) }
status?.let { nbt.putString(DataKeys.POKEMON_STATUS_NAME, it) }
minPerfectIVs?.let { nbt.putInt(DataKeys.POKEMON_MIN_PERFECT_IVS, it) }
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
evs?.let { nbt.put(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
type?.let { nbt.putString(DataKeys.ELEMENTAL_TYPE, it) }
@@ -657,6 +685,7 @@ open class PokemonProperties {
originalTrainer?.let { nbt.putString(DataKeys.POKEMON_ORIGINAL_TRAINER, it) }
moves?.let { nbt.putString(DataKeys.POKEMON_PROPERTIES_MOVES, it.joinToString(separator = ",")) }
heldItem?.let {nbt.putString(DataKeys.POKEMON_PROPERTIES_HELDITEM, it)}
scaleModifier?.let { nbt.putFloat(DataKeys.POKEMON_SCALE_MODIFIER, it) }
val custom = ListTag()
customProperties.map { StringTag.valueOf(it.asString()) }.forEach { custom.add(it) }
nbt.put(DataKeys.POKEMON_PROPERTIES_CUSTOM, custom)
@@ -678,6 +707,7 @@ open class PokemonProperties {
nature = if (tag.contains(DataKeys.POKEMON_NATURE)) tag.getString(DataKeys.POKEMON_NATURE) else null
ability = if (tag.contains(DataKeys.POKEMON_ABILITY)) tag.getString(DataKeys.POKEMON_ABILITY) else null
status = if (tag.contains(DataKeys.POKEMON_STATUS_NAME)) tag.getString(DataKeys.POKEMON_STATUS_NAME) else null
minPerfectIVs = if (tag.contains(DataKeys.POKEMON_MIN_PERFECT_IVS)) tag.getInt(DataKeys.POKEMON_MIN_PERFECT_IVS) else null
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) IVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_IVS)).result().getOrNull()?.first else null
evs = if (tag.contains(DataKeys.POKEMON_EVS)) EVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_EVS)).result().getOrNull()?.first else null
type = if (tag.contains(DataKeys.ELEMENTAL_TYPE)) tag.getString(DataKeys.ELEMENTAL_TYPE) else null
@@ -689,6 +719,7 @@ open class PokemonProperties {
originalTrainer = if (tag.contains(DataKeys.POKEMON_ORIGINAL_TRAINER)) tag.getString(DataKeys.POKEMON_ORIGINAL_TRAINER) else null
moves = if (tag.contains(DataKeys.POKEMON_PROPERTIES_MOVES)) tag.getString(DataKeys.POKEMON_PROPERTIES_MOVES).split(",") else null
heldItem = if (tag.contains(DataKeys.POKEMON_PROPERTIES_HELDITEM)) tag.getString(DataKeys.POKEMON_PROPERTIES_HELDITEM) else null
scaleModifier = if (tag.contains(DataKeys.POKEMON_SCALE_MODIFIER)) tag.getFloat(DataKeys.POKEMON_SCALE_MODIFIER) else null
val custom = tag.getList(DataKeys.POKEMON_PROPERTIES_CUSTOM, Tag.TAG_STRING.toInt())
// This is kinda gross
custom.forEach { customProperties.addAll(parse(it.asString).customProperties) }
@@ -712,6 +743,7 @@ open class PokemonProperties {
nature?.let { json.addProperty(DataKeys.POKEMON_NATURE, it) }
ability?.let { json.addProperty(DataKeys.POKEMON_ABILITY, it) }
status?.let { json.addProperty(DataKeys.POKEMON_STATUS_NAME, it) }
minPerfectIVs?.let { json.addProperty(DataKeys.POKEMON_MIN_PERFECT_IVS, it) }
ivs?.let { json.add(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
evs?.let { json.add(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
type?.let { json.addProperty(DataKeys.ELEMENTAL_TYPE, it) }
@@ -723,6 +755,7 @@ open class PokemonProperties {
originalTrainer?.let { json.addProperty(DataKeys.POKEMON_ORIGINAL_TRAINER, it) }
moves?.let { json.addProperty(DataKeys.POKEMON_PROPERTIES_MOVES, it.joinToString(separator = ",")) }
heldItem?.let {json.addProperty(DataKeys.POKEMON_PROPERTIES_HELDITEM, it)}
scaleModifier?.let { json.addProperty(DataKeys.POKEMON_SCALE_MODIFIER, it) }
val custom = JsonArray()
customProperties.map { it.asString() }.forEach { custom.add(it) }
json.add(DataKeys.POKEMON_PROPERTIES_CUSTOM, custom)
@@ -745,6 +778,7 @@ open class PokemonProperties {
nature = json.get(DataKeys.POKEMON_NATURE)?.asString
ability = json.get(DataKeys.POKEMON_ABILITY)?.asString
status = json.get(DataKeys.POKEMON_STATUS_NAME)?.asString
minPerfectIVs = json.get(DataKeys.POKEMON_MIN_PERFECT_IVS)?.asInt
ivs = json.getAsJsonObject(DataKeys.POKEMON_IVS)?.let { IVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
evs = json.getAsJsonObject(DataKeys.POKEMON_EVS)?.let { EVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
type = json.get(DataKeys.ELEMENTAL_TYPE)?.asString
@@ -756,6 +790,7 @@ open class PokemonProperties {
originalTrainer = json.get(DataKeys.POKEMON_ORIGINAL_TRAINER)?.asString
moves = json.get(DataKeys.POKEMON_PROPERTIES_MOVES)?.asString?.split(",")
heldItem = json.get(DataKeys.POKEMON_PROPERTIES_HELDITEM)?.asString
scaleModifier = json.get(DataKeys.POKEMON_SCALE_MODIFIER)?.asFloat
val custom = json.get(DataKeys.POKEMON_PROPERTIES_CUSTOM)?.asJsonArray
// This is still kinda gross
custom?.forEach { customProperties.addAll(parse(it.asString).customProperties) }
@@ -777,6 +812,7 @@ open class PokemonProperties {
nature?.let { pieces.add("nature=$it") }
ability?.let { pieces.add("ability=$it") }
status?.let { pieces.add("status=$it") }
minPerfectIVs?.let { pieces.add("min_perfect_ivs=$it") }
ivs?.forEach{ stat ->
pieces.add("${stat.key}_iv=${stat.value}")
}
@@ -793,6 +829,7 @@ open class PokemonProperties {
customProperties.forEach { pieces.add(it.asString()) }
moves?.let { pieces.add("moves=${it.joinToString(separator = ",")}") }
heldItem?.let {pieces.add("helditem=$it")}
scaleModifier?.let { pieces.add("scale_modifier=$it") }
return pieces.joinToString(separator)
}
@@ -806,8 +843,8 @@ open class PokemonProperties {
return PokemonProperties().loadFromJSON(this.saveToJSON())
}
// If the config value is at least 1, then do 1/x and use that as the property chance
private fun Float.checkRate(): Boolean = if (this >= 1) (Random.Default.nextFloat() < 1 / this) else Random.Default.nextFloat() < this
// If the config value is at least 0, then do 1/x and use that as the property chance
private fun Float.checkRate(): Boolean = this > 0 && (Random.nextFloat() < 1 / this)
/**
* Attempts to find an ability by ID and resolve if it should be forced or if it's legal for the given form.
@@ -39,7 +39,6 @@ import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
import com.cobblemon.mod.common.api.spawning.TimeRange
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.adapters.ElementalTypeAdapter
@@ -129,7 +128,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
.registerTypeAdapter(RidingBehaviourSettings::class.java, RidingBehaviourSettingsAdapter)
.registerTypeAdapter(RidingStatDefinition::class.java, RidingStatDefinitionAdapter)
.registerTypeAdapter(RideSoundSettingsList::class.java, RideSoundSettingsListAdapter)
.registerTypeAdapter(ObtainableItemCondition::class.java, ObtainableItemConditionAdapter)
.disableHtmlEscaping()
@@ -144,8 +142,10 @@ object PokemonSpecies : JsonDataRegistry<Species> {
private val speciesByIdentifier = hashMapOf<ResourceLocation, Species>()
private val speciesByDex = HashBasedTable.create<String, Int, Species>()
@JvmStatic
val species: Collection<Species>
get() = this.speciesByIdentifier.values
@JvmStatic
val implemented: List<Species>
get() = this.species.filter { it.implemented }
@@ -171,6 +171,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
* @param name The path of the species asset.
* @return The [Species] if existing.
*/
@JvmStatic
fun getByName(name: String) = this.getByIdentifier(cobblemonResource(name))
/**
@@ -179,6 +180,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
* @param ndex The [Species.nationalPokedexNumber].
* @return The [Species] if existing.
*/
@JvmStatic
fun getByPokedexNumber(ndex: Int, namespace: String = Cobblemon.MODID) = this.speciesByDex.get(namespace, ndex)
/**
@@ -187,6 +189,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
* @param identifier The unique [Species.resourceIdentifier] of the [Species].
* @return The [Species] if existing.
*/
@JvmStatic
fun getByIdentifier(identifier: ResourceLocation) = this.speciesByIdentifier[identifier]
/**
@@ -194,6 +197,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
*
* @return The loaded species amount.
*/
@JvmStatic
fun count() = this.speciesByIdentifier.size
/**
@@ -201,6 +205,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
*
* @return The dex numbers map to species.
*/
@JvmStatic
fun getSpeciesInNamespace(namespace: String = Cobblemon.MODID): MutableMap<Int, Species> = speciesByDex.row(namespace)
/**
@@ -208,6 +213,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
*
* @return The list of loaded namespaces.
*/
@JvmStatic
fun getNamespaces() = speciesByDex.rowKeySet().toList()
/**
@@ -217,6 +223,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
*
* @return A randomly selected [Species].
*/
@JvmStatic
fun random(): Species = this.implemented.random()
override fun reload(data: Map<ResourceLocation, Species>) {
@@ -316,4 +323,4 @@ object PokemonSpecies : JsonDataRegistry<Species> {
}
return result
}
}
}
@@ -9,8 +9,9 @@
package com.cobblemon.mod.common.api.pokemon.aspect
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.api.ai.config.task.PollinateFlowerTaskConfig
import com.cobblemon.mod.common.api.spawning.influence.SaccharineLogSlatheredInfluence
import com.cobblemon.mod.common.api.spawning.prospecting.LurePokeSnackDetector
import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import net.minecraft.core.particles.BlockParticleOption
import net.minecraft.core.particles.ParticleOptions
@@ -22,11 +23,12 @@ import net.minecraft.resources.ResourceLocation
*/
val aspectParticleMap: Map<String, ParticleData> = mapOf(
SaccharineLogSlatheredInfluence.HONEY_DRENCHED_ASPECT to ParticleData.MinecraftParticle(ParticleTypes.FALLING_HONEY, 0.075, 1),
LurePokeSnackDetector.POKE_SNACK_CRUMBED_ASPECT to ParticleData.MinecraftParticle(
PokeSnackBlockEntity.POKE_SNACK_CRUMBED_ASPECT to ParticleData.MinecraftParticle(
BlockParticleOption(
ParticleTypes.BLOCK,
CobblemonBlocks.POKE_SNACK.defaultBlockState()
), 0.05, 3),
PollinateFlowerTaskConfig.HAS_NECTAR_ASPECT to ParticleData.MinecraftParticle(ParticleTypes.FALLING_NECTAR, 0.075, 1)
)
sealed class ParticleData {
@@ -36,12 +36,16 @@ object ShoulderEffectRegistry {
PlatformEvents.SERVER_PLAYER_LOGIN.subscribe { this.refreshEffects(it.player) }
}
@JvmStatic
fun register(name: String, effect: Class<out ShoulderEffect>) = effect.also { effects[name] = it }
@JvmStatic
fun unregister(name: String) = effects.remove(name)
@JvmStatic
fun getName(clazz: Class<out ShoulderEffect>) = effects.firstNotNullOf { if (it.value == clazz) it.key else null }
@JvmStatic
fun get(name: String): Class<out ShoulderEffect>? = effects[name]
// It was removed by a source such as milk, reapply
@@ -62,10 +62,14 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
data.forEach(this::registerFromAssets)
}
@JvmStatic
fun getCodeFeature(name: String) = codeFeatures[name]
@JvmStatic
fun getResourceFeature(name: String) = resourceFeatures[name]
@JvmStatic
fun getFeature(name: String) = getCodeFeature(name) ?: getResourceFeature(name)
@JvmStatic
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
@@ -83,7 +87,9 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
mapping[name] = provider
}
@JvmStatic
fun register(name: String, provider: SpeciesFeatureProvider<*>) = register(name, provider, isCoded = true)
@JvmStatic
fun <T : SpeciesFeature> register(name: String, providerLambda: () -> T) {
register(name, object : SpeciesFeatureProvider<T> {
override fun invoke(pokemon: Pokemon) = providerLambda()
@@ -93,6 +99,7 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
}
private fun registerFromAssets(identifier: ResourceLocation, provider: SpeciesFeatureProvider<*>) = register(identifier.path, provider, isCoded = false)
@JvmStatic
fun unregister(name: String) {
var coded = true
val value = getResourceFeature(name)?.also { coded = false } ?: getCodeFeature(name) ?: return
@@ -60,5 +60,6 @@ object SpeciesFeatureAssignments : JsonDataRegistry<SpeciesFeatureAssignment> {
this.assignments.putAll(data)
}
@JvmStatic
fun getFeatures(species: Species) = assignments[species.resourceIdentifier] ?: emptySet()
}
@@ -68,14 +68,19 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
data.forEach(this::registerFromAssets)
}
@JvmStatic
fun getCodeFeature(name: String) = codeFeatures[name]
@JvmStatic
fun getResourceFeature(name: String) = resourceFeatures[name]
@JvmStatic
fun getFeature(name: String) = getCodeFeature(name) ?: getResourceFeature(name) ?: GlobalSpeciesFeatures.getFeature(name)
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
codeFeatures.putAll(entries.map { it.toPair() })
}
@JvmStatic
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
@JvmStatic
fun getFeaturesFor(species: Species): List<SpeciesFeatureProvider<*>> {
val mentionedFeatures = species.features.mapNotNull(this::getFeature)
val globalFeatures = GlobalSpeciesFeatures.getFeatures()
@@ -95,9 +100,11 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
mapping[name] = provider
}
@JvmStatic
fun register(name: String, provider: SpeciesFeatureProvider<*>) = register(name, provider, isCoded = true)
private fun registerFromAssets(identifier: ResourceLocation, provider: SpeciesFeatureProvider<*>) = register(identifier.path, provider, isCoded = false)
@JvmStatic
fun unregister(name: String) {
var coded = true
val value = getResourceFeature(name)?.also { coded = false } ?: getCodeFeature(name) ?: return
@@ -29,6 +29,7 @@ object HeldItemProvider {
* @param pokemon The [Pokemon] being queried.
* @return The [HeldItemManager] that can provide for the given [pokemon], if non match returns the [HeldItemManager.EMPTY].
*/
@JvmStatic
fun provide(pokemon: BattlePokemon): HeldItemManager = this.managers.firstOrNull { manager -> manager.showdownId(pokemon) != null } ?: HeldItemManager.EMPTY
/**
@@ -37,6 +38,7 @@ object HeldItemProvider {
* @param pokemon The [Pokemon] being queried.
* @return The showdownId string that [pokemon] is holding, otherwise null.
*/
@JvmStatic
fun provideShowdownId(pokemon: BattlePokemon) = this.managers.firstNotNullOfOrNull { manager -> manager.showdownId(pokemon) }
/**
@@ -45,6 +47,8 @@ object HeldItemProvider {
* @param manager The [HeldItemManager] being registered.
* @param priority The [Priority] to register it under.
*/
@JvmStatic
@JvmOverloads
fun register(manager: HeldItemManager, priority: Priority = Priority.NORMAL) {
this.managers.add(priority, manager)
}
@@ -56,6 +60,8 @@ object HeldItemProvider {
* @param priority The [Priority] to specifically remove the instance from, if null it will remove from all.
*/
@Suppress("unused")
@JvmStatic
@JvmOverloads
fun unregister(manager: HeldItemManager, priority: Priority? = null) {
if (priority != null) {
this.managers.remove(priority, manager)
@@ -69,6 +75,7 @@ object HeldItemProvider {
*
* @return The read-only copy of the registered [HeldItemManager]s.
*/
@JvmStatic
fun managers(): List<HeldItemManager> = this.managers.toList()
}
@@ -34,17 +34,24 @@ object Statuses {
private val volatileStatuses = mutableListOf<Status>()
private val allStatuses = mutableListOf<Status>()
@JvmField
val POISON = registerStatus(PoisonStatus())
@JvmField
val POISON_BADLY = registerStatus(PoisonBadlyStatus())
@JvmField
val PARALYSIS = registerStatus(ParalysisStatus())
@JvmField
val SLEEP = registerStatus(SleepStatus())
@JvmField
val FROZEN = registerStatus(FrozenStatus())
@JvmField
val BURN = registerStatus(BurnStatus())
@JvmField
val ATTRACT = registerStatus(AttractStatus())
@JvmField
val CONFUSE = registerStatus(ConfuseStatus())
@JvmStatic
fun <T: Status> registerStatus(status: T) : T {
if (status is PersistentStatus) {
persistentStatuses.add(status)
@@ -56,7 +63,10 @@ object Statuses {
return status
}
@JvmStatic
fun getStatus(name: ResourceLocation) = allStatuses.find { status -> status.name == name }
@JvmStatic
fun getStatus(showdownName: String) = allStatuses.find { it.showdownName == showdownName }
@JvmStatic
fun getPersistentStatuses() = persistentStatuses
}
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.reactive.pipes.StopAfterTransform
import com.cobblemon.mod.common.api.reactive.pipes.TakeFirstTransform
import java.lang.Thread.sleep
import java.util.concurrent.CompletableFuture
import java.util.function.Consumer
/**
* An object that emits values of the generic type. This can be subscribed to and unsubscribed from, as well as
@@ -30,6 +31,8 @@ import java.util.concurrent.CompletableFuture
*/
interface Observable<T> {
fun subscribe(priority: Priority = Priority.NORMAL, handler: (T) -> Unit): ObservableSubscription<T>
fun subscribe(handler: Consumer<T>): ObservableSubscription<T> = subscribe(Priority.NORMAL) { handler.accept(it) }
fun subscribe(priority: Priority, handler: Consumer<T>): ObservableSubscription<T> = subscribe(priority) { handler.accept(it) }
fun unsubscribe(subscription: ObservableSubscription<T>)
// This isn't pretty, ik
@@ -103,6 +103,18 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
*/
fun damageOnCollision(settings: Settings, state: State, vehicle: PokemonEntity, impactVec: Vec3): Boolean = false
/**
* Called in [com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer] to allow the controller to set rotations
* through code using partialTicks and right before rendering.
* //TODO: This needs to be further refined. Maybe only the orientationController needs affected? Maybe the rotations set here don't need to be applied to the controller/camera
*/
fun applyRenderRotation(settings: Settings, state: State, vehicle: PokemonEntity, partialTicks: Float) {}
/**
* Determines if the pair of mouse inputs Pair(mouseX, mouseY) get used to modify the driverRotations or the vehicle rotations themselves.
* Driver rotations are the rotations used by passengers or a driver that is freelooking. This does not override the freelook button.
*/
fun mouseModifiesDriverRotation(settings: Settings, state: State, vehicle: PokemonEntity): Pair<Boolean, Boolean> = Pair(false, false)
/**
* Internal helpers to help behaviour specific calculations
Loaded 100 of 3352 files, more files were not shown because too many files have changed in this diff. Show more