Compare commits

..
Author SHA1 Message Date
apion b36f84178e Merge remote-tracking branch 'origin/main' into feature/flashback-compat
# Conflicts:
#	fabric/src/main/resources/mixins.cobblemon-fabric.json
2025-11-26 20:33:51 -05:00
Polymeta 635f29e1ac fix glass bottle not being returned when using honey on saccharine leaves
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 22:08:12 +00:00
Polymeta db2001b60a Merge branch 'attempted-jvm-fix' into 'main'
Fixed JVM crash from campfire pot

Closes #1795

See merge request cable-mc/cobblemon!2040
2025-11-26 21:40:30 +00:00
HirokuandPolymeta b5098a2ad0 Fixed JVM crash from campfire pot 2025-11-26 21:40:29 +00:00
Polymeta 8c939ee276 Merge branch 'lets-wind-down' into 'main'
Fixes wind charges recalling pastured pokémon

Closes #1805

See merge request cable-mc/cobblemon!2042
2025-11-26 13:27:12 +00:00
NeovitalismandPolymeta 645b8993c8 Fixes wind charges recalling pastured pokémon 2025-11-26 13:27:12 +00:00
Polymeta d96799cac7 Merge branch 'feature/neoforge-recipe-book' into 'main'
split recipebooktype and category across fabric and neoforge so we can leverage neoforge APIs

Closes #1789 and #1787

See merge request cable-mc/cobblemon!2044
2025-11-26 12:44:06 +00:00
Polymeta b822b626c4 split recipebooktype and category across fabric and neoforge so we can leverage neoforge APIs 2025-11-26 12:44:05 +00:00
Polymeta 4d9b182fb3 fix hearty grains crashing if a block is in the way
Closes #1818

Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 11:59:25 +00:00
Polymeta 88d155eaf4 [skip-ci] more changelog
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-26 11:33:57 +00:00
Paul af96469b7a changelog [skip-ci] 2025-11-26 21:17:15 +10:00
Paul 65f1e7a3be Merge remote-tracking branch 'weblate/lang-updates' 2025-11-26 21:14:31 +10:00
阿鱼andWeblate 16cd2de02f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.4% (8973 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-26 10:03:51 +00:00
Polymeta 22a44bd7e9 Merge branch 'ImprovedPastureBees' into 'main'
Improved Pasture Combees and More

See merge request cable-mc/cobblemon!2043
2025-11-26 09:36:28 +00:00
Polymeta d37bd4ef03 Merge branch 'OmnipathNavigationCrashFix' into 'main'
OmnipathNavigationCrashFix

See merge request cable-mc/cobblemon!2045
2025-11-26 09:34:03 +00:00
Hiroku a3d9a10f2e Merge branch 'wallpaper' into 'main'
Remove auto generated screen glow due to rendering issues

See merge request cable-mc/cobblemon!2047
2025-11-26 08:48:00 +00:00
Test 7801e3feee changelog clarification [skip-ci] 2025-11-26 04:56:10 +00:00
Test 4a54cb4674 remove auto generated screen glow 2025-11-26 04:38:14 +00:00
JazzMcNade 24fe1c125c changelog 2025-11-25 21:47:45 -06:00
JazzMcNade 023160f87a Removed a really silly cast 2025-11-25 21:32:17 -06:00
Polymeta 17fbf7c6f0 defensive pokemon casts as NPCs use this too
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-25 16:53:26 +00:00
Polymeta ec86b7d4bf fix tag reference
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-25 15:18:09 +00:00
阿鱼andWeblate 7561eb116f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.3% (8960 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-25 14:20:09 +00:00
Polymeta 6467b97a23 Merge branch 'implement_pokemon' into 'main'
marked furfrou as implemented

See merge request cable-mc/cobblemon!2041
2025-11-25 12:16:02 +00:00
JazzMcNade 6d5909a1e3 Added rain clause, do not attempt to enter a full hive, changelog 2025-11-25 02:17:28 -06:00
JazzMcNade 2bb0d43ca8 Fix wandering for pastured bees, fix hoverpos not being cleared 2025-11-25 00:51:04 -06:00
Watuneni iteiteandWeblate 1fb3f0ebdc Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-25 06:46:07 +00:00
violet fb2154e2c3 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-24 22:06:34 -05:00
violet 3b14d19fdb marked furfrou as implemented 2025-11-24 22:06:22 -05:00
Carmendar 6840c2fdef Merge branch 'main' into implement_pokemon 2025-11-24 17:28:35 -06:00
阿鱼andWeblate 8fc2031806 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-24 21:23:59 +00:00
Alexis SalgueiroandWeblate 4795e2e1bc Translated using Weblate (French)
Currently translated at 99.6% (8984 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-11-24 11:22:45 +00:00
Carmendar c563627b05 Shiny female Combee is now actually shiny. 2025-11-24 02:31:25 -06:00
violet 73ebf7a789 tiny typo fix 2025-11-24 03:18:38 -05:00
Landon a1b3d3d2ca Merge branch 'lets-be-friends-again' into 'main'
Move friendship logic to spawn action

See merge request cable-mc/cobblemon!2037
2025-11-24 06:50:24 +00:00
lionandLandon 8baacbcf90 Move friendship logic to spawn action 2025-11-24 06:50:23 +00:00
Hiroku f2e357b749 Merge branch 'pc-crash-fix' into 'main'
Fix PC crash with VulkanMod

Closes #1793

See merge request cable-mc/cobblemon!2038
2025-11-24 04:28:32 +00:00
Test b95900b29a Fix PC crash with VulkanMod 2025-11-23 22:39:28 -05:00
Hiroku 03585fafb0 Merge branch 'HoneyIForgotTheNectar' into 'main'
Don't Forget the Nectar

See merge request cable-mc/cobblemon!2031
2025-11-24 01:38:14 +00:00
washashu0905andWeblate e3d0252d75 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 94.4% (8519 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-11-24 00:10:57 +00:00
阿鱼andWeblate dbe8e57341 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.2% (8950 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-24 00:10:56 +00:00
Zack the GhastandWeblate 6f37fd69cd Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.4% (8791 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2025-11-24 00:10:55 +00:00
JazzMcNade b191f4e9fb Check hivecooldown memory registration 2025-11-23 15:42:56 -06:00
Hiroku a5a7cc20ba Merge branch 'eating-cough-drops' into 'main'
Throat Spray Recipe

See merge request cable-mc/cobblemon!2036
2025-11-23 11:48:00 +00:00
Polymeta 02b6c46082 [skip-ci] 1.7 tag doc files
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-23 11:39:39 +00:00
dhi_holo 881a30cca4 Merge branch 'main' into eating-cough-drops 2025-11-23 20:33:20 +10:00
dhi_holo d01011f4d0 Throat Spray Recipe
This either was lost at some point or never existed in the mod, I'm not sure which. It's here now!
2025-11-23 20:32:21 +10:00
Landon 309ed379c7 Merge branch 'AAAAAAAAAAAAAAAAAAAAA' into 'main'
unfudge camera maybe please

See merge request cable-mc/cobblemon!2030
2025-11-23 10:30:50 +00:00
Landon Wills edbf667f45 Add changelog 2025-11-23 04:44:02 -05:00
Landon Wills b6bc766adf Merge branch 'main' into AAAAAAAAAAAAAAAAAAAAA 2025-11-23 04:42:52 -05:00
Test 1ecf556cf2 Merge branch 'nom' into 'main'
Small Fixes

See merge request cable-mc/cobblemon!2035
2025-11-23 03:46:33 +00:00
dhi_holo 6d32073604 Small Fixes
- Ponigiri can no longer be eaten at full hunger
- Medicinal Brew's Campfire Pot recipe now correctly displays that it can be made using an empty glass bottle or a filled bottle
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader
- Reduced cost of the Vivichoke Seed trade with the Wandering Trader
2025-11-23 12:45:18 +10:00
Hiroku aa0f5d8a05 Merge branch 'vanilla-ride-fix-and-misc-ride-fixes' into 'main'
Fix vanilla rides suffocating players and misc cobble riding fixes

See merge request cable-mc/cobblemon!2033
2025-11-22 23:50:31 +00:00
jackowes 6202c14215 - changelog update 2025-11-22 16:42:20 -06:00
Hiroku b0790341c7 Merge branch 'some-fixes' into 'main'
Some fixes

See merge request cable-mc/cobblemon!2032
2025-11-22 22:36:17 +00:00
jackowes 4f0fa6af4a - Fix horse player suffocation on vanilla mounts
- stop passengers from hearing the shiny noise of a ridden shiny pokemon.
- Convert the riding freelook button to a configurable keybinding

(cherry picked from commit 6432db9f7d)
2025-11-22 16:24:25 -06:00
JazzMcNade 4e24e09924 Safer memory reading in hive occupant mixins 2025-11-22 16:19:30 -06:00
jackowes 48676067b7 Revert "- Fix horse player suffocation on vanilla mounts"
This reverts commit 6432db9f7d.
2025-11-22 16:16:17 -06:00
jackowes 6432db9f7d - Fix horse player suffocation on vanilla mounts
- stop passengers from hearing the shiny noise of a ridden shiny pokemon.
- Convert the riding freelook button to a configurable keybinding
2025-11-22 16:13:47 -06:00
Test 2cb28fb384 rm unused imports 2025-11-22 12:57:59 -05:00
JazzMcNade 3b59148151 changelog again 2025-11-22 11:43:44 -06:00
JazzMcNade d6198631ba New Changelog 2025-11-22 11:40:03 -06:00
geumuandWeblate 47daea6195 Translated using Weblate (Korean)
Currently translated at 75.6% (6826 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 17:37:36 +00:00
Watuneni iteiteandWeblate aca66a4bb0 Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 17:37:35 +00:00
Test e9fe1774c0 fix poke snack sound issue, prevent ride controls from showing to passengers 2025-11-22 12:36:31 -05:00
JazzMcNade bb8b8a77c9 Fixed bees forgetting that they had nectar upon entering a hive 2025-11-22 11:07:37 -06:00
Paul c692b6b5c1 Reset changelog [skip-ci] 2025-11-22 23:09:37 +10:00
geumuandWeblate 68c6d5d9b2 Translated using Weblate (Korean)
Currently translated at 75.6% (6825 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 07:33:14 +00:00
Landon Wills 221547aabf unfuck camera maybe please 2025-11-21 22:39:19 -05:00
Watuneni iteiteandWeblate f6b3591d80 Translated using Weblate (Japanese)
Currently translated at 99.2% (8954 of 9019 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 03:06:51 +00:00
geumuandWeblate f9878d6137 Translated using Weblate (Korean)
Currently translated at 75.2% (6740 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-22 01:45:14 +00:00
Watuneni iteiteandWeblate 94da3b8d21 Translated using Weblate (Japanese)
Currently translated at 100.0% (8962 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-22 01:45:14 +00:00
Nick 3a2ff9de75 1.7.1 SNAPSHOT in prep for next development cycle 2025-11-21 17:06:08 -08:00
Paul b249896316 more changelog [skip-ci] 2025-11-22 09:37:51 +10:00
Test 1cb6979b90 More changelog cleanup [skip-ci] 2025-11-21 20:56:30 +00:00
Polymeta e983d2c1db Merge branch 'implement_pokemon' into 'main'
marked togedemaru as implemented

See merge request cable-mc/cobblemon!2029
2025-11-21 20:16:07 +00:00
violet 9ee0cf941b Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-21 14:29:35 -05:00
violet 8436c93317 marked togedemaru as implemented 2025-11-21 14:29:19 -05:00
Paul 7f0329acb7 Loads of changelog restructuring, separated old versions out into their own files [skip-ci] 2025-11-21 23:49:00 +10:00
Polymeta 83489b7230 nothing to see here
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-21 13:09:27 +00:00
Landon 081a25f04b Merge branch 'does-anyone-even-read-these' into 'main'
Fix mutation of vector after changing from Vector3f to Vec3

See merge request cable-mc/cobblemon!2028
2025-11-21 12:42:41 +00:00
Landon Wills 38bdfae0db Fix mutation of vector after changing from Vector3f to Vec3 2025-11-21 06:57:06 -05:00
Landon bd3a9e30f1 Merge branch 'fix-npc-behavior-json' into 'main'
Fix NPC Behavior Json key

See merge request cable-mc/cobblemon!2026
2025-11-21 11:02:11 +00:00
Hiroku 7ce968f467 Merge branch 'implement_pokemon' into 'main'
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...

See merge request cable-mc/cobblemon!2027
2025-11-21 10:33:34 +00:00
Hiroku 9ac8cc56f0 Merge branch 'main' into 'implement_pokemon'
# Conflicts:
#   common/src/main/resources/data/cobblemon/species/generation5/patrat.json
#   common/src/main/resources/data/cobblemon/species/generation9/tadbulb.json
2025-11-21 09:45:22 +00:00
Polymeta 98159e1e0e Merge branch 'smeargle-tail-reset' into 'main'
Fixed smeargle tail changing colour between relogs

See merge request cable-mc/cobblemon!2024
2025-11-21 09:44:00 +00:00
violet 025b5aae74 edited treecko line, braixen, and delphox's files 2025-11-21 04:27:03 -05:00
Deltric 2fddb21585 Fixed NPC behavior key fix, yes that's right behavior not behaviour @Hiroku. 2025-11-21 01:32:54 -06:00
violet 6b75976236 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 2025-11-21 02:17:36 -05:00
Paul fdf419ec8f Rescraped for willFlee scraper bug, restoring flee behaviour for hundreds of pokes 2025-11-21 17:12:20 +10:00
Paul d2ceb2d58a Fixed wooper and whiscash forms being fished by all rods 2025-11-21 17:11:11 +10:00
Hiroku 6d8311a66c Merge branch '1.7-spawns-update' into 'main'
Updated spawns for 1/100 chance form Pokémon.

See merge request cable-mc/cobblemon!2025
2025-11-21 07:07:00 +00:00
Veraxiel 18a3d1c22c Updated spawns for 1/100 chance form Pokémon. 2025-11-21 01:54:50 -05:00
Hiroku b382a1b2db Merge branch '1.7-tag-cleanup' into 'main'
1.7 tag cleanup

See merge request cable-mc/cobblemon!2017
2025-11-21 06:29:22 +00:00
Paul dd17fa138e Fixed smeargle tail changing colour between relogs 2025-11-21 16:27:56 +10:00
Test 09dd623ea7 Amend dolphin controls overlay 2025-11-21 06:24:56 +00:00
Landon 8c01bb831f Merge branch 'path-faster-and-less-and-faster' into 'main'
Following the owner should not be so aggressive. Path cooldown, and consider...

See merge request cable-mc/cobblemon!2019
2025-11-21 06:09:10 +00:00
Paul 2cb4372496 Removed cry from slowpoke tail'ing 2025-11-21 15:04:43 +10:00
Hiroku 7597b2d98e Merge branch 'fated-faint' into 'main'
Crafting Fix

See merge request cable-mc/cobblemon!2023
2025-11-21 04:54:05 +00:00
dhi_holo 5ac2729a77 Crafting Fix
EV Feathers now unlock in recipe book, and Mochi cannot be crafted in a table, now requires campfire pot cooking
2025-11-21 14:46:13 +10:00
Hiroku bec1fca7a5 Merge branch 'brewer-only' into 'main'
Quick Brewing Only-ification

See merge request cable-mc/cobblemon!2022
2025-11-21 04:19:04 +00:00
dhi_holo 32d145f3cc Quick Brewing Only-ification
Removed 8 recipes that were meant to be removed, added translation for a newer tag that was missed over
2025-11-21 13:34:52 +10:00
Paul a5f1a14e21 Merge remote-tracking branch 'weblate/lang-updates'
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/pt_br.json
2025-11-21 11:43:28 +10:00
Landon 57784b8620 Merge branch 'camera-farlands' into 'main'
Switch to using Doubles when positioning camera.

See merge request cable-mc/cobblemon!2021
2025-11-20 23:28:26 +00:00
JPAKx4 a29b3342a1 Switch to using Doubles when positioning camera. 2025-11-20 16:41:13 -06:00
Polymeta 64d6560caf Merge branch 'cobble-jail-here-i-come' into 'main'
Small fixes

See merge request cable-mc/cobblemon!2018
2025-11-20 22:10:32 +00:00
Polymeta 2e314e48fb Merge branch 'Car-fixes' into 'main'
Car fixes

See merge request cable-mc/cobblemon!2016
2025-11-20 21:19:50 +00:00
Nick e8d1e3766b Merge branch 'fix-pc-deserialisation' into 'main'
Fix PC JSON loading

See merge request cable-mc/cobblemon!2020
2025-11-20 12:09:54 -08:00
Landon Wills 012682268e Add safe check for nbt 2025-11-20 14:22:32 -05:00
Landon Wills 38428e4ea9 Fix PC JSON loading 2025-11-20 14:19:17 -05:00
Paul 567132bc0c Even more aggressive optimizations for the nodemaker 2025-11-20 23:07:59 +10:00
Paul e7209e4000 More aggressive optimizations for the nodemaker 2025-11-20 22:40:19 +10:00
Landon Wills 273b520c0b Shave iterations off of node type checks 2025-11-20 02:13:27 -05:00
Guilherme Pereira 0f02313a14 prevent pokemon from being busy when capturing player gets killed 2025-11-20 03:13:55 -03:00
Guilherme Pereira 3249e4bbb1 prevent pokemon from doing damage when being captured 2025-11-20 03:13:15 -03:00
geumuandWeblate 36aca65003 Translated using Weblate (Korean)
Currently translated at 67.0% (6010 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-20 05:48:24 +00:00
Watuneni iteiteandWeblate c6635213a2 Translated using Weblate (Japanese)
Currently translated at 99.2% (8897 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-20 05:48:23 +00:00
JazzMcNade bf6fab3936 Only check for nearby danger nodes if the hitbox is small 2025-11-19 23:18:11 -06:00
Watuneni iteiteandWeblate b76158d1d7 Translated using Weblate (Japanese)
Currently translated at 99.2% (8896 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-20 02:32:39 +00:00
geumuandWeblate 916ec97fce Translated using Weblate (Korean)
Currently translated at 66.6% (5972 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-20 02:32:36 +00:00
Veraxiel 36b38d36cb Updated biome tags. 2025-11-19 21:00:27 -05:00
Veraxiel f1163977e1 Updated biome and seasoning tags. Updated Sinister Tea recipe filter. 2025-11-19 20:59:42 -05:00
Carmendar a7dd6d52c8 Charizard and Mudsdale Look tweaks. 2025-11-19 19:29:19 -06:00
Watuneni iteiteandWeblate 6898804e83 Translated using Weblate (Japanese)
Currently translated at 96.9% (8686 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-20 00:40:19 +00:00
Carmendar 2331603b27 Tyrantrum sleep t-pose fix. 2025-11-19 18:30:38 -06:00
Carmendar c8e9cbbe59 Furfrou cry fix 2025-11-19 18:30:11 -06:00
Carmendar d374635648 Aerodactyl Battle Cry and Texture fix 2025-11-19 18:29:39 -06:00
Polymeta 803d3be325 recipe and tag tweak
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-19 23:59:55 +00:00
Polymeta 50bacbe25e Merge branch 'fix_medicinal_brew_from_cooking_pot_recipe' into 'main'
Revert Medicinal Brew recipe back to water bottle as opposed to empty bottle.

See merge request cable-mc/cobblemon!2015
2025-11-19 23:55:28 +00:00
Faintful 94ef9830b7 Revert Medicinal Brew recipe back to water bottle as opposed to empty bottle. 2025-11-19 21:17:22 +01:00
Weblate 87502f36c4 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-19 16:43:18 +00:00
Nico MerenqandWeblate bed511d403 Translated using Weblate (Russian)
Currently translated at 78.3% (7019 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-19 16:43:14 +00:00
阿鱼andWeblate 4170b00e31 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (8962 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-19 16:43:13 +00:00
geumuandWeblate 3cc90daaf0 Translated using Weblate (Korean)
Currently translated at 66.2% (5937 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-19 16:43:12 +00:00
Polymeta b0ecd24f42 Merge branch 'aprijuice-advancement-fix' into 'main'
Fixed max ride boosts advancement not working properly

See merge request cable-mc/cobblemon!2014
2025-11-19 14:10:10 +00:00
Polymeta ade5603331 Edit max_ride_stats.json 2025-11-19 13:25:03 +00:00
Paul 34bcefb09f Fixed max ride boosts advancement not working properly 2025-11-19 21:41:14 +10:00
Hiroku dccc9dfbcb Merge branch 'sterr/sound-fixes' into 'main'
Audio fixes stuff

See merge request cable-mc/cobblemon!2013
2025-11-19 11:29:40 +00:00
Weblate 9a1d6461d9 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-19 11:12:29 +00:00
Watuneni iteiteandWeblate 2dc76ffe3e Translated using Weblate (Japanese)
Currently translated at 96.4% (8646 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-19 11:12:25 +00:00
geumuandWeblate 87225d8981 Translated using Weblate (Korean)
Currently translated at 65.6% (5886 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-19 11:12:24 +00:00
Sterrezo 4bf4101fd1 Audio fixes stuff 2025-11-19 11:39:24 +01:00
Paul 58c6ea0269 Following the owner should not be so aggressive. Path cooldown, and consider hitbox when deciding if it needs to start walking closer 2025-11-19 19:16:42 +10:00
Paul 034bd2eec6 Only use strict walking pathing when the hitbox is small 2025-11-19 19:16:02 +10:00
Polymeta a24be04d68 Merge branch 'ihatebugtypes1.7' into 'main'
sacrificing Bugsy for the sake of the release

Closes #1771 and #1768

See merge request cable-mc/cobblemon!2000
2025-11-19 07:32:27 +00:00
Segfault Guy 0d878d57b7 Merge remote-tracking branch 'origin/main' into ihatebugtypes1.7 2025-11-19 00:55:42 -05:00
Paul 08880e2294 Fixed instance of check for diagonal validation on non pokemon 2025-11-19 12:52:20 +10:00
Paul 1c45654930 Update the changed-default root variables on 1.7 installation 2025-11-19 12:33:36 +10:00
Hiroku dae3acb5a0 Merge branch 'i-dont-know-what-to-call-this-branch' into 'main'
Small fixes

See merge request cable-mc/cobblemon!2007
2025-11-19 02:30:20 +00:00
Hiroku 7bb6f8a12e Merge branch 'damage-formula' into 'main'
Add attack to damage formula

See merge request cable-mc/cobblemon!2011
2025-11-19 02:18:25 +00:00
lionandHiroku b25f3ca3f6 Add attack to damage formula 2025-11-19 02:18:25 +00:00
Hiroku 610b762188 Merge branch 'nut-rition' into 'main'
Food Tweaks

See merge request cable-mc/cobblemon!2010
2025-11-19 02:00:41 +00:00
Hiroku c4c954c898 Merge branch 'Meta&Jet-fixes' into 'main'
Metagross fix and Jet handling tweak.

See merge request cable-mc/cobblemon!2009
2025-11-19 01:49:19 +00:00
Segfault Guy 10b70a0e3f Merge remote-tracking branch 'origin/main' into ihatebugtypes1.7 2025-11-18 20:20:46 -05:00
Segfault Guy af437f9d3e Merge branch 'ihatebugtypes1.7' of https://gitlab.com/cable-mc/cobblemon into ihatebugtypes1.7 2025-11-18 20:14:21 -05:00
Segfault Guy ca5a96e979 Fix berry chomp sfx not playing for unrestricted berries when full. 2025-11-18 20:11:02 -05:00
dhi_holo a2936ebcff Berry Reorganisation
Reordered berries as Vera requested
2025-11-19 11:10:15 +10:00
geumuandWeblate c3d7537b3e Translated using Weblate (Korean)
Currently translated at 65.0% (5832 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-19 00:43:57 +00:00
Carmendar 81e5d830c6 Metagross walks once more & Jet handling expression tweak. 2025-11-18 18:38:02 -06:00
dhi_holo 4b09714ed5 Merge branch 'main' into nut-rition 2025-11-19 10:27:33 +10:00
Polymeta fa4a4c7e51 Merge branch 'farming-simulator-2025' into 'main'
Allow villagers to plant hearty rice

See merge request cable-mc/cobblemon!2008
2025-11-19 00:25:29 +00:00
dhi_holo 493b8bbecf Seasoning Tweaks
values are now what they should be, hopefully
2025-11-19 10:23:56 +10:00
Guilherme Pereira 9b519daff1 allow villagers to plant hearty rice 2025-11-18 21:02:10 -03:00
Guilherme Pereira a5ba3e7084 buff roots 2025-11-18 19:23:38 -03:00
Guilherme Pereira 6d2d146543 sync combat behaviour 2025-11-18 19:17:13 -03:00
Landon 22d93cb92c Merge branch 'navigator-performance' into 'main'
Performance optimizations for pathfinding

See merge request cable-mc/cobblemon!2006
2025-11-18 18:41:03 +00:00
geumuandWeblate 31c55a9b6f Translated using Weblate (Korean)
Currently translated at 65.0% (5832 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-18 17:39:25 +00:00
Paul 5281dbd81c Performance optimizations for pathfinding 2025-11-19 03:02:52 +10:00
Segfault Guy 8b863070fe addressing MR comments 2025-11-18 11:20:07 -05:00
Paul da1064772d Fixed rattata cry crash 2025-11-19 01:59:00 +10:00
Landon 8ca1957a60 Merge branch 'ai-scrape' into 'main'
Scraped AI and Behaviors

See merge request cable-mc/cobblemon!1994
2025-11-18 12:51:11 +00:00
lionandLandon cbab2b7e5c Scraped AI and Behaviors 2025-11-18 12:51:10 +00:00
Landon c47bd604d5 Merge branch 'wrong-land-shark' into 'main'
Prevent sharpedo from trying to swim on land

See merge request cable-mc/cobblemon!2003
2025-11-18 12:21:59 +00:00
Polymeta 63776ca7a0 added missing food colours and remove debug annotation
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-18 11:56:32 +00:00
Polymeta c66c7170f6 Merge branch 'juice-tweaks' into 'main'
Fixed apricorn stat changes only applying when points are already assigned to that stat, adjusted flavour floor

See merge request cable-mc/cobblemon!2004
2025-11-18 10:00:03 +00:00
Weblate e9e4158666 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-18 09:44:12 +00:00
Watuneni iteiteandWeblate b15917898f Translated using Weblate (Japanese)
Currently translated at 95.7% (8582 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-18 09:44:07 +00:00
TeggyandWeblate ef3179bfa2 Translated using Weblate (Spanish)
Currently translated at 84.8% (7602 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-11-18 09:44:06 +00:00
阿鱼andWeblate f0afb8b3d9 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.9% (8959 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-18 09:44:05 +00:00
geumuandWeblate 17e58b0ce5 Translated using Weblate (Korean)
Currently translated at 63.7% (5714 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-18 09:44:04 +00:00
Paul fb0bfb2d19 Merge remote-tracking branch 'origin/main' 2025-11-18 19:42:15 +10:00
Landon 0d87de157a Merge branch 'implement_pokemon' into 'main'
Implemplemenation

See merge request cable-mc/cobblemon!2002
2025-11-18 09:35:33 +00:00
Paul 4189da0cc7 Merge remote-tracking branch 'origin/main' 2025-11-18 19:33:17 +10:00
Paul 662ccdc268 Removed unrefined sinister tea seasonings 2025-11-18 19:29:54 +10:00
Hiroku 6779995680 Merge branch 'evo_particles_fix' into 'main'
Claire Obscure Particles: Expedition 33

See merge request cable-mc/cobblemon!1997
2025-11-18 09:26:28 +00:00
Landon c4b6cc7c00 Merge branch 'slowpoke-dex-fix' into 'main'
Fixed some dex display issues and fixed slowpoke appearance in dex

See merge request cable-mc/cobblemon!2001
2025-11-18 09:24:09 +00:00
Paul 07ef404518 Fixed apricorn stat changes only applying when points are already assigned to that stat, adjusted flavour floor 2025-11-18 19:13:04 +10:00
Landon Wills 4c8a8351ac Prevent sharpedo from trying to swim on land 2025-11-18 04:06:57 -05:00
Carmendar 17f5ed03d0 poser/species tweaks. 2025-11-18 02:46:11 -06:00
Paul a3d3c987bc Fixed some dex display issues and fixed slowpoke appearance in dex 2025-11-18 18:34:46 +10:00
Carmendar 6db0567f03 Merge branch 'main' into implement_pokemon 2025-11-18 02:02:32 -06:00
Segfault Guy 3e89499588 Fix SocketShowdownService and custom showdown data registration. 2025-11-18 02:09:39 -05:00
Segfault Guy 7982034964 Fix missing optional ability activation langs. 2025-11-18 02:02:19 -05:00
Jackson Bowes ac3628d907 Merge branch 'ufo-turning-and-head-rot-fix' into 'main'
Fix various bugs with riding.

See merge request cable-mc/cobblemon!1998
2025-11-18 00:32:11 -06:00
Segfault Guy 4a1e0020f7 remove redundant bag item 2025-11-18 01:10:12 -05:00
Segfault Guy 3c1486e45b Implement volatile status curing berries and patch fullness conflict with restoration berries. 2025-11-18 00:36:11 -05:00
jackowes 4563770835 - fix nonJumping horses from falling through to Tpose when trying to jump. The in_air flag checks for the player.jumping flag so its true for a moment. Block this from being true when horse has no jump. 2025-11-17 23:00:13 -06:00
dhi_holo c49eed3aaf Initial value tweaks 2025-11-18 14:59:28 +10:00
jackowes cc80f69c47 - Fix jet bug/mishap
- Fixed ride sounds not working in multiplayer
- Made the velocity threshold lower for ridesounds so that they can be heard in more 'normal' situations.
- Revert player head rotation changes for rollables.
2025-11-17 22:56:30 -06:00
Landon 128366f9c2 Merge branch '1.7-spawns-update' into 'main'
Updated spawns for Marill, Bidoof, Rufflet, and Tadbulb lines.

See merge request cable-mc/cobblemon!1996
2025-11-18 04:43:51 +00:00
Tyzillion 1d158ae12c Evolution obscure particles fixed. 2025-11-17 23:10:58 -05:00
Landon ddd63ac841 Merge branch 'Aprijuice-Recipe-Change' into 'main'
Energy Root added to Aprijuice recipes & slight update to compost values.

See merge request cable-mc/cobblemon!1995
2025-11-18 03:57:18 +00:00
Veraxiel 118a682451 Updated spawns for Marill, Bidoof, Rufflet, and Tadbulb lines. 2025-11-17 22:26:13 -05:00
Landon d202efc0a9 Merge branch 'validate-op-permissions-riding' into 'main'
Add is OP player check to riding stats debug GUI

See merge request cable-mc/cobblemon!1988
2025-11-18 03:16:00 +00:00
Carmendar 81a1314493 Energy Root added to Aprijuice recipes & slight update to compost values. 2025-11-17 21:08:16 -06:00
Guilherme Pereira d20673d9bf fix pokemon not being able to enter boats 2025-11-17 21:32:30 -03:00
FrankTheFarmer 4634dc7539 Fixed both stunfisks using portrait pose when in water 2025-11-18 09:56:52 +10:00
FrankTheFarmer c2db648d25 Tweaked Rayqwayqway's poser 2025-11-18 08:59:33 +10:00
FrankTheFarmer 76f1ace6b7 Fixed scovillain's cry interpolation 2025-11-18 08:51:15 +10:00
Jackson Bowes a316329359 Merge branch 'very-minor-molang-change' into 'main'
Fix boats and truthy values

See merge request cable-mc/cobblemon!1993
2025-11-17 16:29:54 -06:00
violet 4aa1b804bc Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-17 17:25:32 -05:00
violet 233d27413d poser tweaks to tynamo, ribombee, and cutiefly 2025-11-17 17:25:24 -05:00
FrankTheFarmer 05621ccb51 Merge branch 'main' into implement_pokemon 2025-11-18 08:13:24 +10:00
jackowes ea59981b58 - fix ufo momentum by rotating the rideVelocity vector by the induced ride yaw. 2025-11-17 15:22:41 -06:00
JPAKx4 960460ec08 Fix Boats being 'in_air' in water and vice versa. 2025-11-17 13:58:06 -06:00
JPAKx4 8d587c5287 Fix unintendid behaviour, shouldn't actually change anything currently though. 2025-11-17 13:35:19 -06:00
Guilherme Pereira e0b79c9bab change is op check to use cobblemon permissions validator 2025-11-17 09:36:56 -03:00
Polymeta 6206330b76 Merge branch 'getting-statistical' into 'main'
Getting statistical and minor Advancement fixes

See merge request cable-mc/cobblemon!1760
2025-11-17 09:30:28 +00:00
FrankTheFarmer 8e7a2a0356 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-17 19:29:51 +10:00
FrankTheFarmer 7657cf4f73 Fixed Dragapult spinning rapidly after every physical attack 2025-11-17 19:28:59 +10:00
Polymeta 7b137fbe14 Merge branch 'Saccharine-Tree-Biome-List-Update' into 'main'
Saccharine tree biome list update

See merge request cable-mc/cobblemon!1990
2025-11-17 09:21:35 +00:00
Landon 4d472d0b36 Merge branch 'molang-json-interaction' into 'main'
Molang json interaction

See merge request cable-mc/cobblemon!1934
2025-11-17 09:10:40 +00:00
Slippy fd442211d3 Change Saccharine Tree Rarity 2025-11-17 03:07:58 -06:00
Landon 144f857a3b Merge branch 'fix-blocks-traveled-requirement' into 'main'
Fix Blocks Traveled requirement

See merge request cable-mc/cobblemon!1979
2025-11-17 08:20:35 +00:00
lionandLandon 80131e57f8 Fix Blocks Traveled requirement 2025-11-17 08:20:35 +00:00
Slippy 30d89a2704 Make Saccharine Trees a little less common 2025-11-17 02:04:51 -06:00
Landon 5e147545b7 Merge branch 'advancing-advancements' into 'main'
Advancing Advancements for Cobblemon 1.7.0

See merge request cable-mc/cobblemon!1974
2025-11-17 07:59:41 +00:00
Landon e962079cda Merge branch 'remove-poke-puff' into 'main'
Disable Poké Puffs temporarily

See merge request cable-mc/cobblemon!1989
2025-11-17 07:30:41 +00:00
lionandLandon 6f934cfbd4 Disable Poké Puffs temporarily 2025-11-17 07:30:41 +00:00
MoeBoy76 47ecef81a6 fix changelog errors 2025-11-17 18:02:04 +11:00
MoeBoy76 16762ae933 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical 2025-11-17 17:56:53 +11:00
MoeBoy76 ba47f6a833 remove species check from catch trigger 2025-11-17 17:56:26 +11:00
dhi_holo 522ffefd0a Stone fix and Z-fix
All Evolution Stone blocks (besides Nether Fire Stone Ore) now need Iron to mine, and Display Cases now look better in more contexts
2025-11-17 16:04:15 +10:00
dhi_holo e17ca360df Merge branch 'main' into advancing-advancements 2025-11-17 15:46:04 +10:00
Carmendar a559737106 Merge branch 'main' into implement_pokemon 2025-11-16 23:27:00 -06:00
Landon e18d5837af Merge branch 'riding-molang-electric-bogaloo' into 'main'
Switch asMoLangValue from the states to the behaviour to allow for more dynamic options.

See merge request cable-mc/cobblemon!1986
2025-11-17 05:15:10 +00:00
Landon 65ae67d9ac Merge branch 'disable-nvb' into 'main'
Disable third_person_view_bobbing Config.

See merge request cable-mc/cobblemon!1987
2025-11-17 05:15:08 +00:00
Paul 05c77a6156 Hitbox improvements for melee attack, also don't randomly attack piglins or slimes or creepers 2025-11-17 15:11:50 +10:00
Paul 8ae6792785 Fixed fossil substitutes not working, fixed aspects not working in fossil tank rendering, fixed slowpoke tail aspects being added to everything 2025-11-17 11:21:23 +10:00
Guilherme Pereira 5f67fc167a add is op player check to riding stats debug gui 2025-11-16 20:16:08 -03:00
FrankTheFarmer 8dd62269ed Updated delphox animations 2025-11-17 08:03:29 +10:00
JPAKx4 0eee6e8634 Merge remote-tracking branch 'origin/riding-molang-electric-bogaloo' into riding-molang-electric-bogaloo
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/air/BirdBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/air/HoverBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/air/JetBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/air/RocketBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/land/HorseBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/land/MinekartBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/land/VehicleBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/liquid/BoatBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/liquid/BurstBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/liquid/DolphinBehaviour.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/riding/behaviour/types/liquid/SubmarineBehaviour.kt
2025-11-16 15:10:45 -06:00
JPAKx4 a16a7c31fe Switch asMoLangValue from the states to the behaviour to allow for more dynamic options. 2025-11-16 15:10:07 -06:00
Apion a6c02cc63e Fix server crash 2025-11-16 13:29:02 -05:00
JPAKx4 a4254df0ca Disable third_person_view_bobbing Config. 2025-11-16 12:02:25 -06:00
JPAKx4 21df52daf7 Switch asMoLangValue from the states to the behaviour to allow for more dynamic options. 2025-11-16 11:49:08 -06:00
Landon 5e81e26c69 Merge branch 'molang-riding' into 'main'
Updates to riding to work better in Molang

See merge request cable-mc/cobblemon!1984
2025-11-16 15:33:38 +00:00
Hiroku d103629fd2 Merge branch '1.7-spawns-update' into 'main'
1.7 spawns update

See merge request cable-mc/cobblemon!1983
2025-11-16 09:27:54 +00:00
JPAKx4andJordan 6e2a0cd3b9 Switch to using ObjectValues for states to support riding styles with multiple properties. Added a few useful properties that can now be accessed through get_riding_state(name). 2025-11-16 07:12:59 +00:00
Apion fc229298e7 Fix bug where Flashback didn't track some driver state when the recorder was driving 2025-11-16 01:36:25 -05:00
FrankTheFarmer 77490783e4 Swampert model tweak to fix its look animation 2025-11-16 15:51:10 +10:00
FrankTheFarmer ed28c70c5a Tweaked Meganium's profile data to look better in the dex 2025-11-16 15:50:40 +10:00
FrankTheFarmer 3f71584a6e Clamped Shelmet's look range to stop clipping with the shell. 2025-11-16 14:55:31 +10:00
FrankTheFarmer 4f09e56510 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-16 14:54:36 +10:00
FrankTheFarmer b534183a50 Clamped Sandaconda's look range and stopped it from using the donut to look 2025-11-16 14:54:27 +10:00
Carmendar 56ea6c7161 Merge branch 'main' into implement_pokemon 2025-11-15 22:48:16 -06:00
Veraxiel 37f6010381 Edit to Popplio line spawns. 2025-11-15 23:44:38 -05:00
Hiroku 798dd64f84 Merge branch 'RestoreSheepShearing' into 'main'
Restore Sheep Shearing

See merge request cable-mc/cobblemon!1982
2025-11-16 03:43:58 +00:00
Paul c1acf8494c Slowpoke tails are snipped a bit less short 2025-11-16 13:15:44 +10:00
Veraxiel d4601326a7 Removed Water and Lava block tags. Updated spawns using those tags to use the blocks directly. 2025-11-15 22:09:50 -05:00
JazzMcNade a037af6948 Allow herding sheep to eat grass, fix typo 2025-11-15 20:55:58 -06:00
FrankTheFarmer 976c94cb6b Puppy and Icecream changelog 2025-11-16 12:48:28 +10:00
FrankTheFarmer 422154e4c7 Tweaked Eevee's shoulder positioning 2025-11-16 12:46:38 +10:00
JazzMcNade 517ac94b8d Restore sheep shearing and eating grass to restore wool 2025-11-15 20:26:31 -06:00
Apion 3a0239a01f Fix crash with flashback related to improper riding packet handling 2025-11-15 21:23:17 -05:00
Apion 2dc027ec5f Fix bug with flashback where riding state was not properly updates 2025-11-15 21:22:48 -05:00
Paul b5ec2b28fd Merge remote-tracking branch 'origin/main' 2025-11-16 12:14:50 +10:00
Paul f45a4b784b Fixed percentSum being exceeded during multi-pass spawns, closes #1778 2025-11-16 12:14:35 +10:00
Hiroku 91dda046d8 Merge branch 'revert-transition-logic' into 'main'
Revert transition logic so land mounts can be consistently mounted

See merge request cable-mc/cobblemon!1981
2025-11-16 01:47:59 +00:00
FrankTheFarmer 71fabbd245 Added placeholder shoulder animations to Alcremie 2025-11-16 11:45:07 +10:00
Carmendar fa0f29b085 Merge branch 'main' into implement_pokemon 2025-11-15 18:57:34 -06:00
Landon Wills 49577d2518 Revert transition logic so land mounts can be consistently mounted 2025-11-15 19:29:36 -05:00
FrankTheFarmer 12de6750de Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-16 10:19:01 +10:00
FrankTheFarmer 4e1b9785a0 Stupid fish assets updated 🔵🔴⚪ 2025-11-16 10:18:53 +10:00
RedGenesectNinja 2f2de32493 Implemented the updated textures for Slowpoke and Galarian Slowpoke 2025-11-15 18:09:39 -06:00
FrankTheFarmer a38b68ce23 Added translucent culling to flygon's resolver to fix goggle z fighting 2025-11-16 09:49:09 +10:00
FrankTheFarmer 7d605f8bf9 Updated flygon's animation to fix the static legs in the ground idle 2025-11-16 09:48:46 +10:00
FrankTheFarmer 75134f41e3 Fixed flygon's look animation to use the proper head_ai bone 2025-11-16 09:48:20 +10:00
Landon 2bad8ec673 Merge branch 'implement_pokemon' into 'main'
Implement pokemon

See merge request cable-mc/cobblemon!1945
2025-11-15 22:44:48 +00:00
Carmendar 1524e9c476 smol species fixes. 2025-11-15 15:55:14 -06:00
Carmendar c8ad0cd7e7 Merge branch 'main' into implement_pokemon
# Conflicts:
#	common/src/main/resources/data/cobblemon/species/generation1/aerodactyl.json
#	common/src/main/resources/data/cobblemon/species/generation1/arcanine.json
#	common/src/main/resources/data/cobblemon/species/generation1/blastoise.json
#	common/src/main/resources/data/cobblemon/species/generation1/charizard.json
#	common/src/main/resources/data/cobblemon/species/generation1/dewgong.json
#	common/src/main/resources/data/cobblemon/species/generation1/dragonite.json
#	common/src/main/resources/data/cobblemon/species/generation1/gyarados.json
#	common/src/main/resources/data/cobblemon/species/generation1/lapras.json
#	common/src/main/resources/data/cobblemon/species/generation1/mrmime.json
#	common/src/main/resources/data/cobblemon/species/generation1/nidoking.json
#	common/src/main/resources/data/cobblemon/species/generation1/parasect.json
#	common/src/main/resources/data/cobblemon/species/generation1/rhydon.json
#	common/src/main/resources/data/cobblemon/species/generation1/rhyhorn.json
#	common/src/main/resources/data/cobblemon/species/generation1/seaking.json
#	common/src/main/resources/data/cobblemon/species/generation1/tauros.json
#	common/src/main/resources/data/cobblemon/species/generation1/venusaur.json
#	common/src/main/resources/data/cobblemon/species/generation2/ariados.json
#	common/src/main/resources/data/cobblemon/species/generation2/forretress.json
#	common/src/main/resources/data/cobblemon/species/generation2/girafarig.json
#	common/src/main/resources/data/cobblemon/species/generation2/heracross.json
#	common/src/main/resources/data/cobblemon/species/generation2/piloswine.json
#	common/src/main/resources/data/cobblemon/species/generation2/ursaring.json
#	common/src/main/resources/data/cobblemon/species/generation3/altaria.json
#	common/src/main/resources/data/cobblemon/species/generation3/camerupt.json
#	common/src/main/resources/data/cobblemon/species/generation3/claydol.json
#	common/src/main/resources/data/cobblemon/species/generation3/flygon.json
#	common/src/main/resources/data/cobblemon/species/generation3/latias.json
#	common/src/main/resources/data/cobblemon/species/generation3/latios.json
#	common/src/main/resources/data/cobblemon/species/generation3/metagross.json
#	common/src/main/resources/data/cobblemon/species/generation3/relicanth.json
#	common/src/main/resources/data/cobblemon/species/generation3/salamence.json
#	common/src/main/resources/data/cobblemon/species/generation3/sharpedo.json
#	common/src/main/resources/data/cobblemon/species/generation3/slaking.json
#	common/src/main/resources/data/cobblemon/species/generation3/tropius.json
#	common/src/main/resources/data/cobblemon/species/generation3/wailmer.json
#	common/src/main/resources/data/cobblemon/species/generation3/wailord.json
#	common/src/main/resources/data/cobblemon/species/generation4/bastiodon.json
#	common/src/main/resources/data/cobblemon/species/generation4/bronzong.json
#	common/src/main/resources/data/cobblemon/species/generation4/drifblim.json
#	common/src/main/resources/data/cobblemon/species/generation4/dusknoir.json
#	common/src/main/resources/data/cobblemon/species/generation4/garchomp.json
#	common/src/main/resources/data/cobblemon/species/generation4/gastrodon.json
#	common/src/main/resources/data/cobblemon/species/generation4/lickilicky.json
#	common/src/main/resources/data/cobblemon/species/generation4/magnezone.json
#	common/src/main/resources/data/cobblemon/species/generation4/mamoswine.json
#	common/src/main/resources/data/cobblemon/species/generation4/rhyperior.json
#	common/src/main/resources/data/cobblemon/species/generation4/staraptor.json
#	common/src/main/resources/data/cobblemon/species/generation4/togekiss.json
#	common/src/main/resources/data/cobblemon/species/generation5/bouffalant.json
#	common/src/main/resources/data/cobblemon/species/generation5/braviary.json
#	common/src/main/resources/data/cobblemon/species/generation5/crustle.json
#	common/src/main/resources/data/cobblemon/species/generation5/darmanitan.json
#	common/src/main/resources/data/cobblemon/species/generation5/golurk.json
#	common/src/main/resources/data/cobblemon/species/generation5/hydreigon.json
#	common/src/main/resources/data/cobblemon/species/generation5/klinklang.json
#	common/src/main/resources/data/cobblemon/species/generation5/serperior.json
#	common/src/main/resources/data/cobblemon/species/generation5/volcarona.json
#	common/src/main/resources/data/cobblemon/species/generation5/zebstrika.json
#	common/src/main/resources/data/cobblemon/species/generation6/gogoat.json
#	common/src/main/resources/data/cobblemon/species/generation6/noivern.json
#	common/src/main/resources/data/cobblemon/species/generation6/skiddo.json
#	common/src/main/resources/data/cobblemon/species/generation6/tyrantrum.json
#	common/src/main/resources/data/cobblemon/species/generation7/dhelmise.json
#	common/src/main/resources/data/cobblemon/species/generation7/mudsdale.json
#	common/src/main/resources/data/cobblemon/species/generation8/corviknight.json
#	common/src/main/resources/data/cobblemon/species/generation8/dragapult.json
#	common/src/main/resources/data/cobblemon/species/generation8a/sneasler.json
#	common/src/main/resources/data/cobblemon/species/generation8a/ursaluna.json
#	common/src/main/resources/data/cobblemon/species/generation8a/wyrdeer.json
#	common/src/main/resources/data/cobblemon/species/generation9/cyclizar.json
#	common/src/main/resources/data/cobblemon/species/generation9/dondozo.json
#	common/src/main/resources/data/cobblemon/species/generation9/dudunsparce.json
#	common/src/main/resources/data/cobblemon/species/generation9/espathra.json
#	common/src/main/resources/data/cobblemon/species/generation9/farigiraf.json
#	common/src/main/resources/data/cobblemon/species/generation9/kilowattrel.json
#	common/src/main/resources/data/cobblemon/species/generation9/orthworm.json
#	common/src/main/resources/data/cobblemon/species/generation9/revavroom.json
2025-11-15 15:53:14 -06:00
Apion 230cb02afe Revert "Add gross fix for flashback only."
This reverts commit 3f458bd210.
2025-11-15 14:28:36 -05:00
Kenji_64 33a4e31b60 Fixed Wartortle's shiny shell not being green 2025-11-15 19:51:14 +01:00
Nico MerenqandWeblate 250724ef1f Translated using Weblate (Russian)
Currently translated at 77.9% (6988 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-15 15:05:37 +00:00
Patch Notes GuyandWeblate 3e1837543d Translated using Weblate (Ukrainian)
Currently translated at 77.5% (6948 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/uk/
2025-11-15 10:45:37 +00:00
Carmendar 1526c2f037 Merge branch 'main' into implement_pokemon 2025-11-15 04:30:45 -06:00
Carmendar 408cf8c5ca One last poser tweak for the night. 2025-11-15 04:29:59 -06:00
violet ceb70dbf2d Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-15 04:26:14 -05:00
Carmendar 6d46992ad7 More poser tweaks. 2025-11-15 03:25:53 -06:00
violet 84242194ba fixed drampa look 2025-11-15 04:25:52 -05:00
violet 529e4bef46 fixed espurr line posers 2025-11-15 04:07:10 -05:00
violet aa1658bb5d fixed alolan muk's portrait 2025-11-15 03:55:16 -05:00
violet 068df2b138 added eelektross and eelektrik placeholder animations + fixed look animations 2025-11-15 03:47:56 -05:00
Carmendar 3499758203 Darmanitan Zen poser fix. 2025-11-15 00:29:54 -06:00
RedGenesectNinja 7d97df3407 Fixed Shiny Spring, Summer and Winter Sawsbuck using the wrong models 2025-11-15 00:17:06 -06:00
Nico MerenqandWeblate 1add7ea4cb Translated using Weblate (Russian)
Currently translated at 77.1% (6916 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-15 06:14:04 +00:00
Felipe Bermudes OrmeñoandWeblate e497cd445a Translated using Weblate (Spanish (Mexico))
Currently translated at 26.7% (2394 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es_MX/
2025-11-15 06:14:02 +00:00
Carmendar 22b0e0612a Vanillite line shiny textures for real. 2025-11-14 23:57:48 -06:00
Carmendar e52c63d565 Metagross jump stat adjustment. 2025-11-14 23:52:45 -06:00
Carmendar fe7f72cb3d Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-14 23:51:50 -06:00
Carmendar 8187905987 Adjusted walk speed for Gogoat. 2025-11-14 23:51:04 -06:00
RedGenesectNinja 11b3043e6c Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-14 22:47:24 -06:00
RedGenesectNinja 8d871ac949 Fixed Dragonair's shiny not working 2025-11-14 22:47:04 -06:00
Carmendar 8f7a523404 stat tweaks. 2025-11-14 22:40:22 -06:00
JPAKx4 3f458bd210 Add gross fix for flashback only. 2025-11-14 20:47:58 -06:00
JPAKx4 b07ea7566b Merge branch 'main' into feature/flashback-compat 2025-11-14 20:19:49 -06:00
Carmendar bb98992635 Surface mount tweaks. 2025-11-14 20:02:34 -06:00
Landon Wills d3984843e2 Run scraper 2025-11-14 19:32:31 -05:00
Carmendar 7a14c51df2 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-14 18:05:45 -06:00
Carmendar a7b023203f Merge branch 'main' into implement_pokemon 2025-11-14 18:04:18 -06:00
Nico MerenqandWeblate e382e89e06 Translated using Weblate (Russian)
Currently translated at 76.6% (6868 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-14 17:21:23 +00:00
Gustavo PuerariandWeblate faf64a6092 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.2% (8804 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2025-11-14 17:21:21 +00:00
MoeBoy76 2b64174cfe fix input order which causes logic bug 2025-11-15 00:56:58 +11:00
MoeBoy76 918282893c Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical 2025-11-15 00:50:37 +11:00
violet dbbca02619 centiskorch texture tweaks 2025-11-14 05:52:46 -05:00
violet c50d5841d8 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-14 05:51:05 -05:00
violet 5489cfb4b0 fixed bellibolt's look anims 2025-11-14 05:39:07 -05:00
violet e421de547f SLOWPOKE TAILS NOW DROP WHEN YOU KILL THEM 2025-11-14 05:30:24 -05:00
geumuandWeblate aa8d0a9d48 Translated using Weblate (Korean)
Currently translated at 61.5% (5513 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-14 10:22:59 +00:00
violet 075dcdb9e9 BRAND NEW COBBLEMON EXCLUSIVE FURFROU FORMS PROPERLY IMPLEMENTED 2025-11-14 04:53:22 -05:00
Carmendar 2ebe8d6434 breach jump for Dragapult 2025-11-14 02:53:18 -06:00
Carmendar d7c77f5f3f a few ride stats adjusted ahead of scraper 2025-11-14 02:50:10 -06:00
Zack the GhastandWeblate 7a8dbbb4ce Translated using Weblate (Portuguese (Portugal))
Currently translated at 67.6% (6059 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-11-14 08:26:53 +00:00
Watuneni iteiteandWeblate b8e1abc80b Translated using Weblate (Japanese)
Currently translated at 94.6% (8484 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-14 08:26:52 +00:00
YasitoandWeblate 12df9d29f5 Translated using Weblate (French)
Currently translated at 100.0% (8962 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-11-14 08:26:51 +00:00
YasitoandWeblate 2df0542631 Translated using Weblate (French (Canada))
Currently translated at 100.0% (8962 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-11-14 08:26:50 +00:00
dhi_holoandWeblate e22b79a47c Translated using Weblate (English (en_PT))
Currently translated at 28.4% (2550 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/en_PT/
2025-11-14 08:26:49 +00:00
Carmendar 572682a23a Merge branch 'main' into implement_pokemon 2025-11-14 01:36:27 -06:00
Carmendar 6241865f95 Grounded again 2025-11-14 01:34:02 -06:00
dhi_holo 67dbda3113 Final Checks
Fixed the icons being outdated formattings, we are good to gold
2025-11-14 17:33:33 +10:00
Carmendar c50d3183e6 Submarine expression tweak 2025-11-14 01:22:35 -06:00
dhi_holo 9eae394ff5 Merge branch 'advancing-advancements' of https://gitlab.com/cable-mc/cobblemon into advancing-advancements 2025-11-14 17:15:14 +10:00
MoeBoy76 76b640984c changelog
[skip-ci]
2025-11-14 18:13:40 +11:00
dhi_holo 72d142a781 Merge branch 'main' into advancing-advancements 2025-11-14 17:08:21 +10:00
MoeBoy76 af1df22e4d ride stat trigger logic finalisation, added getBaseRideStat method to check the minimum value of a stat and updated the advancement 2025-11-14 18:07:15 +11:00
dhi_holo 66787bfea4 Merge branch 'main' into advancing-advancements 2025-11-14 15:03:10 +10:00
dhi_holo c113e68488 Moomoo Mistake
Fixed lang string for moomoo milk tooltip
2025-11-14 15:03:05 +10:00
Carmendar 8284b04426 Merge branch 'main' into implement_pokemon
# Conflicts:
#	common/src/main/resources/data/cobblemon/species/generation1/rattata.json
#	common/src/main/resources/data/cobblemon/species/generation2/unown.json
#	common/src/main/resources/data/cobblemon/species/generation3/latias.json
#	common/src/main/resources/data/cobblemon/species/generation3/latios.json
#	common/src/main/resources/data/cobblemon/species/generation3/shuppet.json
#	common/src/main/resources/data/cobblemon/species/generation5/hydreigon.json
#	common/src/main/resources/data/cobblemon/species/generation5/volcarona.json
#	common/src/main/resources/data/cobblemon/species/generation9/wiglett.json
2025-11-13 18:16:41 -06:00
Weblate 0c4bbef855 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-13 13:42:34 +00:00
Nico MerenqandWeblate 6fb34b5ee3 Translated using Weblate (Russian)
Currently translated at 76.0% (6819 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-11-13 13:42:29 +00:00
dhi_holoandWeblate f345b19d57 Translated using Weblate (English (en_PT))
Currently translated at 26.7% (2399 of 8962 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/en_PT/
2025-11-13 13:42:29 +00:00
dhi_holo f1bdaad97d Merge branch 'main' into advancing-advancements 2025-11-13 19:29:15 +10:00
dhi_holo f725e5fcba Improve max_ride_stats description 2025-11-13 19:28:40 +10:00
violet 2237e1eeca added missing emissive textures for magmar, magmortar, torracat, incineroar, sizzlipede, & centiskorch 2025-11-13 04:24:36 -05:00
dhi_holo bb54f8414e Merge branch 'main' into advancing-advancements 2025-11-13 18:17:07 +10:00
Carmendar 99c7d39705 Grounded. 2025-11-13 01:42:08 -06:00
Carmendar bdd27078b5 Merge branch 'main' into implement_pokemon 2025-11-13 00:33:06 -06:00
dhi_holo 7c3fdbc921 Merge branch 'main' into advancing-advancements 2025-11-13 14:06:59 +10:00
RedGenesectNinja 9596f08957 Fixed Dusknoir's shiny not working and Updated Bronzong's textures 2025-11-12 21:12:00 -06:00
MoeBoy76 d9433960cd fml, forgot the license 2025-11-13 13:09:02 +11:00
MoeBoy76 89b6fd56b6 Merge remote-tracking branch 'origin/getting-statistical' into getting-statistical 2025-11-13 12:52:58 +11:00
MoeBoy76 10c441e3cd worked out rod casting, updated changelog 2025-11-13 12:52:36 +11:00
MoeBoy76 461b22efa8 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2025-11-13 12:44:17 +11:00
Carmendar 57a19909aa Merge branch 'main' into implement_pokemon 2025-11-12 19:32:00 -06:00
MoeBoy76 dc1473919e riding trigger added, added empty_bait check to reel in trigger 2025-11-13 12:24:16 +11:00
Carmendar ee20986ee0 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-12 19:23:57 -06:00
RedGenesectNinja 436aa5ea75 Updated textures for a handful of Pokemon 2025-11-12 19:14:19 -06:00
Carmendar e49f761417 Poser fixes and cries added. 2025-11-12 19:09:38 -06:00
Carmendar 95e3ab213a anim fixes for Scorbunny and Sneasler 2025-11-12 18:48:14 -06:00
Apion 98f8441c4e Merge remote-tracking branch 'origin/main' into feature/flashback-compat 2025-11-12 14:59:56 -05:00
Carmendar 0c33de61b9 Species file updates for Tauros, Salamence, Latias, Latios and Staraptor. 2025-11-12 03:05:12 -06:00
Carmendar 91a3fb5031 Removed Kilowattrel mounted run. 2025-11-12 03:04:32 -06:00
Carmendar 3a46b2c218 Updated look posing for Tropius, Garchomp and Pidove. 2025-11-12 03:03:28 -06:00
Carmendar 2f631ddc64 Ursaring texture fix 2025-11-12 03:02:39 -06:00
Carmendar 2a2ef6ff7d Removed mount 2025-11-12 02:42:32 -06:00
Carmendar d3d94a3614 Adjusted Dragonite flying pose when mounted. 2025-11-12 02:42:03 -06:00
Carmendar f34cc3072b Cutiefly Shoulder poses. 2025-11-12 02:41:12 -06:00
Carmendar 68bff6a40b Jet Handling expression tweak. 2025-11-12 00:45:26 -06:00
Segfault Guy d1a99608a5 Fix SwapInstruction not updating party positions. 2025-11-11 22:10:50 -05:00
dhi_holo 2a6381d610 Eggant Is Here Now 2025-11-12 10:47:12 +10:00
dhi_holo 93dba4f3b8 Merge branch 'main' into advancing-advancements 2025-11-12 10:43:55 +10:00
Carmendar a7e7c2e814 Merge branch 'main' into implement_pokemon 2025-11-11 17:52:15 -06:00
MoeBoy76 6bf62b3f9d change debug message to log as error 2025-11-11 11:05:38 +00:00
Carmendar 00be470281 Alolan Rattata fix. 2025-11-11 02:58:28 -06:00
Carmendar 57afbe79c2 Orthworm and Honedge line texture fixes. 2025-11-11 00:49:30 -06:00
Carmendar d5f336ce73 Merge branch 'main' into implement_pokemon 2025-11-11 00:48:17 -06:00
violet b79a0b1b6f various animation fixes 2025-11-10 03:17:58 -05:00
violet 57721d1696 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-09 22:51:33 -05:00
violet b0711528d6 tiny tweaks :3 2025-11-09 22:51:19 -05:00
violet 7e968fcff9 Murdered Shulker Forretress 2025-11-09 22:50:41 -05:00
Carmendar e399130fda forgor one last change 2025-11-09 18:45:12 -06:00
Carmendar 0083e54f6a Galar Weezing crash fix 2025-11-09 18:27:38 -06:00
Apion d78c076e06 Use getter instead of field in ReplayGamePacketHandlerMixin 2025-11-09 17:09:49 -05:00
Carmendar 9512252b72 ^ 2025-11-09 14:24:41 -06:00
Carmendar 73028d4c2a Gave Dondozo basic land & fixed pivot issues with Bramblin. 2025-11-09 14:20:58 -06:00
Carmendar 2f5910c436 Merge branch 'main' into implement_pokemon 2025-11-09 03:09:26 -06:00
Carmendar d1197cbc0b Updated Kangaskhan poser & added held item condition. 2025-11-09 02:30:09 -06:00
Carmendar 2ccf699a86 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-09 01:37:47 -06:00
Carmendar d767420814 Wiglett lost floating privileges. 2025-11-09 01:37:08 -06:00
Carmendar 77100300b1 Fixed Luxray feet textures. 2025-11-09 01:35:05 -06:00
Carmendar 5c80fc03e2 Toxicroak remodel 2025-11-09 01:33:55 -06:00
Carmendar aa39bb84fe Fixed Lanturn t-posing on land. 2025-11-09 00:50:19 -06:00
violet a767b3d0fe Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-09 01:28:31 -05:00
violet 3dbcbc34d0 ICE CREAM 2025-11-09 01:28:17 -05:00
violet 0bdadb3794 altered posers for solosis line 2025-11-09 01:20:50 -05:00
Apion 6118a4ed32 Add Flashback mixin to support custom SpawnExtraDataEntityPackets from PokemonEntitys 2025-11-08 23:09:09 -05:00
dhi_holo 05b5782cd5 Merge branch 'main' into advancing-advancements 2025-11-09 12:54:24 +10:00
dhi_holo 0c220a8990 Berry Colour Tags
Small sorting thing to make it easier to find specific berry colours for cooking/crafting/smelting
2025-11-09 12:53:58 +10:00
Apion 8464591e41 Add flashback to dev environment run configs (c2me conflicts, removed temporarily) 2025-11-08 13:17:22 -05:00
dhi_holo da787bf9bf Merge branch 'main' into advancing-advancements 2025-11-07 16:15:29 +10:00
Paul 57a839d000 Removed some test stuff I forgor about 2025-11-06 22:14:08 +10:00
Paul e77e49c8b1 Minor cleanup 2025-11-06 22:13:03 +10:00
Paul ce6d142bd4 Merge remote-tracking branch 'origin/main' into molang-json-interaction 2025-11-06 22:12:17 +10:00
MoeBoy76 f2db63164c general riding and PokéRod cast/reel stats 2025-11-05 16:05:52 +11:00
MoeBoy76 604b4d39ea Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical 2025-11-05 14:26:27 +11:00
Paul 5d3741f2e5 Added JSON file interactions for molang and function arguments for q.run_script 2025-11-02 11:23:50 +10:00
dhi_holo 5e21ac94dc Merge branch 'main' into advancing-advancements 2025-10-25 17:13:13 +10:00
dhi_holo 1d055253d2 Merge branch 'main' into advancing-advancements 2025-10-10 16:00:30 +10:00
dhi_holo d56c5520f9 Merge branch 'main' into advancing-advancements 2025-10-04 17:26:10 +10:00
dhi_holo 89bc893f06 gamerule.healersHealPC 2025-10-04 17:25:50 +10:00
dhi_holo acc8d066e5 stOre 2025-10-03 19:17:00 +10:00
dhi_holo 6608268117 Update cobblemon.json
fixed typo
2025-10-03 14:03:35 +10:00
dhi_holo bdecab25a6 Merge branch 'main' into advancing-advancements 2025-10-03 13:38:45 +10:00
dhi_holo 81ed97a68b Update cobblemon.json
Removed removed item, added new items
2025-09-30 11:03:26 +10:00
dhi_holo 1e051deb9e Update CHANGELOG.md 2025-09-29 18:06:37 +10:00
dhi_holo 38c54e255a Chromatic Upgrades
- Removed Vivichoke advancement
- Reworded Galar Fossil advancement
- Renamed Master Rod advancement, made hidden by default
- Name tweak for IV Candy advancement
- Description update for regional delicacy advancement
- Renamed Poke Bait advancement
- Description update to ride stats
- Removed Aprijuice advancement
- Combined interaction advancements
- Added Saccharine advancement
- Moved Poke Snack advancement
- Updated some icons for advancements
2025-09-29 15:34:14 +10:00
dhi_holo e7ad38d1df Interactions and Clean Up
Added more Interaction based advancements, moved some stuff around, cleaned up visuals and description for max ride stats
2025-09-28 23:13:59 +10:00
dhi_holo 67c0abea8f Better Brush Desc 2025-09-28 21:15:54 +10:00
dhi_holo 85c1543df1 More tweaks
Brushing Pokemon advancement now works swell, Aprijuice advancement good, started work on the concept for Max Ride Stats, still need to actually get a trigger for it though
2025-09-28 17:10:15 +10:00
dhi_holo f38a1f83e2 More
Started on Bait and Brush advancements, renamed A Luring Aroma
2025-09-28 00:36:02 +10:00
dhi_holo 28785a01f6 Update revive.json
Reduced output to 1
2025-09-26 20:04:08 +10:00
dhi_holo 01c4260763 Merge branch 'main' into advancing-advancements 2025-09-25 20:05:09 +10:00
dhi_holo 150b3eb178 Snack 2025-09-25 20:05:07 +10:00
dhi_holo 5ab52d37f2 Fix Typo 2025-09-25 19:50:26 +10:00
dhi_holo ce191fd4c7 3 New, Minor Reorg
New: Cooking Regional Delicacies, Cooking EV Mochi, Cooking Poké Snack
Cleaned Up: Any Plant no longer announces to chat, Battle Win is on root, Use Candy is on Place Campfire Pot (also moves IV Candy to that tree instead)
2025-09-24 19:34:20 +10:00
MoeBoy76 9a7e349101 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical 2025-09-23 09:33:46 +10:00
MoeBoy76 07a7d2a51a Statistics correctly register and if something goes wrong a more helpful crash should be thrown. 2025-09-23 09:33:28 +10:00
MoeBoy76 d2b192cb07 stats still don't register 2025-09-22 13:36:54 +10:00
MoeBoy76 d8e3e93a87 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical 2025-09-22 10:06:52 +10:00
MoeBoy76 af12df38ed stats should work for NF now 2025-09-22 10:05:03 +10:00
MoeBoy76 7fb8268fae Lang tweaks 2025-08-04 10:38:54 +10:00
MoeBoy76 8b49eb1526 Stats work and Advancement fixes to match wiki 2025-08-04 10:19:25 +10:00
MoeBoy76 c6cdcf83a9 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2025-08-04 08:26:06 +10:00
MoeBoy76 4bf82083b4 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical 2025-04-28 09:02:44 +10:00
MoeBoy76 6579fd8ebe more stats work, they load now and have lang 2025-04-23 11:02:12 +10:00
MoeBoy76 4d62ef771a Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into getting-statistical 2025-04-23 10:11:33 +10:00
MoeBoy76 7784a3a20c initial stats work 2025-04-22 09:49:47 +10:00
1547 changed files with 14517 additions and 70555 deletions
+40 -44
View File
@@ -1,58 +1,54 @@
# Changelog
## [1.7.4 (MONTH Xth, 2026)](#1-7-4)
## [1.7.1 (MONTH xth, 2025)](#1-7-1)
### Additions
- Added config options to award experience to fainted Pokémon for opponents they helped defeat (`awardExperienceToFaintedPokemon`) and to still award experience for defeated enemies even after battle loss/forfeit (`awardExperienceOnBattleLoss`)
- Party Overlay Exp Gained Animation will now display the amount of EXP the Pokémon gained
- Added a toast to notify players of how they can scroll through their party. Did you know you can hold R and scroll instead of using arrow keys??!
- Added new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
- Added missing crops to Botany Pots integration
### New rideable Pokémon
### Pokémon Added
### Model updates for the following Pokémon
### Animation updates for the following Pokémon
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader.
- Added brewing recipe for Throat Spray.
### Changes
- Restructured Botany Pots integration folder structure
- Decrease default pastured mon wander radius to 32.
- Factor in the weight of pokemon when calculating pushing forces between hitboxes.
- Remade the Starter Selection Screen with new assets
- Refactored berry trees to be less impactful on TPS (more performant)
- Converted the riding freelook button to a configurable keybinding.
- Reduced the cost of the Vivichoke Seed trade with the Wandering Trader.
### Fixes
- Fixes https://gitlab.com/cable-mc/cobblemon/-/issues/1943
- Fix occasional crash on retrieving revived fossils
- Fixed a compatibility issue with World Game Rules which caused some log spam in specific cases.
- Fixed improper validation of Pokémon when performing a trade.
- Fixed issue where particle like beam can disappear when you don't see the beginning of the beam or you look away
- Fixes https://gitlab.com/cable-mc/cobblemon/-/issues/1943
- Fix occasional crash on retrieving revived fossils
- Fix brushing not working on Neoforge
- [Various Submarine Ride Fixes](https://gitlab.com/cable-mc/cobblemon/-/merge_requests/2157)
- Fix Pastured mons despawning and running away.
- Fix Apricorn trees crashing when other mods bonemeal it
- [Various UFO Ride Improvements](https://gitlab.com/cable-mc/cobblemon/-/merge_requests/2156)
- Fixed NeoForge brewing stand unexpectedly crashing users when shift clicking items within it's menu
- Fixed NPCs switching pokemon very often during battles
- Fixed Campfire pot causing crashes under certain circumstances
- Fixed Type Gems not being consumed upon use
- Fixed Ancient Pokeball's to their respective modifiers
- Fixed a Server warning when recalling Pokemon
- Prevent displaying ride controls overlay to passengers.
- Fixed player suffocation on vanilla mounts experienced on some worlds.
- Fixed Poké Snack spawning sounds not coming from the block.
- Fix player suffocation on vanilla mounts experienced on some worlds.
- Stop passengers from hearing the shiny noise of a ridden shiny Pokémon.
- Fixed incorrect camera pivot on Bird, Jet, and Dolphin mounts.
- Fixed Poké Snack spawning sound positioning.
- Ponigiri can no longer be eaten at full hunger.
- Medicinal Brew's Campfire Pot recipe now correctly displays that it can be made using an empty glass bottle or a filled bottle.
- Fixed a crash when you place a block in the way of hearty grains 2nd block
- Fixed a graphics crash that could occur on some machines when campfires were nearby.
- Fixed glass bottle not being returned when honey-ing a saccharine leaf block
- Fixed Combees not depositing honey upon leaving a hive if they entered with nectar.
- Fixed pastured Combees not moving in night or rain.
- Fixed a case in which a Combee might try to path to a flower that no longer exists.
- Fixed Combees attempting to enter a full hive.
- Fixed a crash involving Combees and hives.
- Fixed crashing and rendering issues when opening a PC box with certain wallpapers.
- Fixed a crash when opening a PC box with certain wallpapers while using *VulkanMod*.
- Fixed a glitch where friendship would reset to the default value when evolving a Pokémon.
- Fixed a crashed related to NPC navigation.
- Fix player suffocation on vanilla mounts experienced on some worlds.
- Stop passengers from hearing the shiny noise of a ridden shiny Pokémon.
- Fixed friendship resetting to the default value when evolving a Pokémon.
- Fixed a bunch of incompatibilities with NeoForge mods
- Fixed a bug where wind charges hitting pasture blocks would recall all pokémon in it.
### Developer
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters
- Added `FishingSpawnerFactory` which allows influence registration on fishing encounters
- Added `BattleFleeAttemptEvent` fired from `PokemonBattle.checkFleeAttempt`, allowing developers to intercept and control flee attempts
### Molang & Datapacks
- q.item.is_enchanted()
- q.item.has_enchantment(minecraft:sharpness, 3)
- Added `has_chosen_starter` & `get_starter_uuid` as available Molang functions
- Added `marks`, `has_mark`, & `remove_marks` as available Molang functions for pokemon
- Removed automatic generation of PC wallpaper screen glow if no asset is provided; it is now optional.
### Particles
### Localization
- Updated translations for:
- French
- Japanese
- Korean
- Brazilian Portuguese
- Simplified Chinese
- Traditional Chinese
-61
View File
@@ -1,61 +0,0 @@
# Changelog
## [1.7.1 (November 29th, 2025)](#1-7-1)
### Additions
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader.
- Added brewing recipe for Throat Spray.
- Added vanilla sprinting's field of view change to Pokémon land mounts.
- Added a customizable keybind for the riding freelook button.
- Added double tap to sprint on land mounts.
### Changes
- Made Jet pitch turning 1.5x faster across all Pokémon.
- Party Pokémon now attack only mobs that are attacking their owner, instead of randomly targeting unrelated mobs and getting themselves hurt.
- Reduced the cost of the Vivichoke Seed trade with the Wandering Trader.
### Fixes
- Fixed incorrect camera pivot on Bird, Jet, and Dolphin mounts, leading to some disorienting riding.
- Fixed players suffocating while on vanilla mounts.
- Fixed a graphics crash that could occur on some machines when campfire pots were nearby.
- Fixed ride controls overlay being displayed to passengers. The passengers probably don't need to know about those.
- Fixed mount jumping so that it doesn't switch back to ground animations.
- Fixed ridden Pokémon land collision and some issues around stepping up blocks. Land mounts are smoother overall now.
- Fixed Furfrou's pink and magenta trims being swapped. Only a man could make that mistake.
- Fixed friendship being reset to the default value when evolving a Pokémon.
- Fixed Combees not depositing honey upon leaving a hive if they entered it with nectar.
- Fixed pastured Combees not moving during the night or in rain.
- Fixed a case in which a Combee might try to path to a flower that no longer exists.
- Fixed Combees attempting to enter a full hive.
- Fixed a crash involving Combees and hives. 500 bee bugs. Bugged bees? We can be bees. Mark, this is good news.
- Fixed a crash related to NPC navigation.
- Fixed a crash when opening a PC box with certain wallpapers while using *VulkanMod*.
- Fixed a crash when you place a block in the way of hearty grains 2nd block.
- Fixed passengers hearing the shiny noise of a ridden shiny Pokémon.
- Ponigiri can no longer be eaten at full hunger.
- Fixed Poké Snack spawning sounds not coming from the block.
- Medicinal Brew's Campfire Pot recipe now correctly displays that it can be made using an empty glass bottle or a filled bottle.
- Fixed glass bottle not being returned when slathering honey on a saccharine leaf block.
- Fixed saccharine hanging signs sometimes dropping their oak wood counterpart when being broken.
- Fixed a bunch of incompatibilities with NeoForge mods.
- Fixed a bug where wind charges hitting pasture blocks would recall all Pokémon in it.
- Fixed the Home on the Range advancement triggering when opening the Pokémon interaction wheel.
- Fixed recipes that use concrete not working on NeoForge.
- Fixed Boltund's model.
- Fixed Cyclizar's textures.
### Developer
### Molang & Datapacks
- Removed automatic generation of PC wallpaper screen glow if no asset is provided; it is now optional.
- This is because there's no practical way to do this without blowing up things like *VulkanMod*.
### Particles
### Localization
- Updated translations for:
- French
- Japanese
- Korean
- Brazilian Portuguese
- Simplified Chinese
- Traditional Chinese
-137
View File
@@ -1,137 +0,0 @@
# Changelog
## [1.7.2 (January 25th, 2026)](#1-7-2)
### Additions
- Added Saccharine wood furniture for Adorn.
- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship.
- Added decorative block models for existing items: Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Ether, Elixir, Max Ether, Max Elixir, X Accuracy, X Attack, X Defence, X Special Attack, X Special Defence, X Speed, Dire Hit, Guard Spec, Weakness Policy, Blunder Policy, Cleanse Tag, and Spell Tag.
- Added decorative sign blocks called Plaques.
- Added ride style labels to ride stats in Pokédex, as well as ride style icons in the summary GUI.
- Added more seasonings for sinister tea:
- Mental Herb - Mental Restoration I for 10 seconds, which staves off Insomnia.
- White Herb - Removes negative effects.
- Milk, Moomoo Milk - Removes effects.
- Added dispenser support for:
- Applying a Honey Bottle to Saccharine Logs.
- Washing honey off of Saccharine Slathered Logs.
- Applying and removing honey on Saccharine Leaves.
- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`.
### New rideable Pokémon
- Honchkrow
- Mantine
### Pokémon Added
#### Gen 5
- Throh
- Sawk
#### Gen 6
- Litleo
- Pyroar
- Spritzee
- Aromatisse
- Swirlix
- Slurpuff
### Model updates for the following Pokémon
- Falinks
- Cottonee
- Whimsicott
- Ferroseed
- Ferrothorn
- Chingling
- Chimecho
### Animation updates for the following Pokémon
- Mantine (ride animations)
- Flygon (ride jump animation)
- Honchkrow (ride animations)
- Croagunk
- Toxicroak
### Changes
- Added a new config option, `Enable In-Flight Dismounting` (default: off), which lets you dismount while riding a Pokémon in the air. This is the textbook definition of caveat emptor.
- Ride sounds have been separated into stereo for passengers and mono for other players. Riding will now sound more spacious.
- Battle AI now uses a smarter threshold for switching, reducing unnecessary switches.
- AI will always use the most damaging move when at low HP and when it is not switching, improving endgame decision-making.
- Items given from interacting with Saccharine Leaves are placed in the active hotbar slot if possible.
- Added `label` as an alternate key to the `tag` property.
### Fixes
- Fixed crashing when viewing another player in spectator mode. Some said this was reason to release this update a month ago. They were probably right.
- Fixed crashing when sending a Pokémon out after editing its form.
- Fixed all Pokémon being saved to chunks and never despawning even when they should be.
- Fixed Poké Snacks crashing if there was no available spawn.
- Fixed Poké Snack / Bait effects so that EV Yield, Type, and Egg Group filters now all apply together when weighting spawns. And you thought you were going crazy.
- Fixed Furfrou not being trimmable on NeoForge specifically.
- Fixed honey from Saccharine Leaves being harvestable at less than the max age.
- Fixed possible error on world generation when Combee are placed in naturally generated bee nests.
- Fixed Galarian Weezing crashing the world if it decides to blink the wrong way. The same could happen to you!
- Fixed Galarian Mr. Mime incorrectly being rideable. Some would argue that regular Mr. Mime shouldn't be rideable, but that would make them wrong.
- Fixed missing apricorn textures for Adorn blocks.
- Fixed Apricorn block model rotation for counters/sinks/cupboards/drawers to match that of most recent version of Adorn.
- Fixed item interaction sometimes not working properly when playing on servers.
- Fixed Mint Leaves not being usable for filling the Resurrection Machine.
- Fixed Super Potion recipes incorrectly using Hondew Berry instead of Aguav Berry. They look similar, to be fair.
- Fixed Wishiwashi not schooling properly.
- Fixed battle item duplication issue. How did it work? Wouldn't you like to know, weather boy.
- Fixed the ordering of Aprijuice's riding stat boosts so they always have the same order.
- Fixed the movesets of certain Pokémon being incorrectly sanitized upon reload, causing some forms to keep losing moves.
- Fixed selected leading Pokémon in battle not being used when levels are set.
- Fixed the bottom half of pasture blocks having an incorrect hit-box when facing north or south.
- Fixed gimmicks not being usable in double and triple battles.
- Fixed gimmick buttons showing when already used in the same turn in double and triple battles.
- Fixed mochi items consuming two items at a time.
- Fixed Fresh Start Mochi's EV reset not syncing health changes properly.
- Fixed Pokémon spawn influences not being specific to regional forms.
- Fixed memory leak from battles not being cleaned up after ending.
- Fixed orientation not getting reset after crashing while flying and getting back on the Pokémon.
- Fixed shiny Pokémon not respecting the `silent` flag on spawn.
- Fixed 'Plain' prefix not being applied to all low-quality Aprijuice.
- Fixed Pokémon interactions not playing sound effects when the volume was not specified.
- Fixed Pokémon interaction cooldowns taking longer than intended when the Pokémon was in the player’s party.
- Fixed Pokémon interactions occasionally crashing the game when spamming an interaction with a 0 cooldown.
- Fixed Pokémon fullness decreasing more than intended when the Pokémon was pastured.
- Fixed Scraggy line, Milcery line, and Morpeko spawning on unnatural blocks.
- Fixed invulnerability-bypassed damage being resisted by invulnerable NPC entities.
- Fixed Fabric network packets not being handled immediately, fixing incompatibilities with Supplementaries, Prometheus, Sleep Tight, and others.
- Fixed killer not being set early enough on a wild Pokémon entity from `WinInstruction`.
- Fixed requirements such as `biomeCondition` crashing the game when used to define Pokémon interactions.
- Fixed an issue that prevented registering custom dispenser behaviours (no longer overrides vanilla behaviour).
- Fixed an issue navigation that prevented Combee from pathing into and out of Saccharine Leaves.
- Added Saccharine Boats and Saccharine Boat with Chests to relevant boat tags.
- Fixed Soothe Bell not being properly tagged as a held item.
- Fixed `/calculateseatpositions` expecting a locator format that even we don't use. It needs an underscore after "seat".
- Fixed the `run_script` Molang function to not fail if the environment's context is null.
- Fixed the Molang functions `date_local_time`, `date_of`, `date_is_after` to use the correct date format.
### Developer
- Changed the `owner` parameter in the `OwnerQueryRequirement` interface from `ServerPlayer` to `Player`. This method is now also called on the client to verify whether a Pokémon interaction succeeded, so make sure to update your implementations to handle both server and client contexts.
- Added the `pnx` to the `BattleFaintedEvent` and `FormeChangeEvent`.
- Added register methods for custom instructions to `ShowdownInterpreter`.
- Changed callback operations in `BattlePokemon` to allow multiple callbacks and be mutable.
- Added `display_name`, `description`, and `max_pp` functions to the `MoveTemplate` struct.
- Changed the implementations of `AIBattleActor` to be open classes to allow extension.
- Changed the resource location of Poké Ball icons in the GUI to use the balls namespace instead of Cobblemon's, allowing mods to properly use their own namespace for these textures.
### Molang & Datapacks
- Ride sounds can now be set as exclusive to passengers.
- Ride sounds no longer play when submerged unless specified with a new setting.
- Exception handling has been added to `run_molang`, resolving some crashes caused by malformed MoLang expressions.
- Added the `create_itemstack`, `has_inventory_space`, `set_inventory_slot`, and `give_item` MoLang functions for item and inventory utility.
- Added the `get_move_from_id` MoLang function for general move info queries without requiring a Moveset object to access.
- Added support for optional message variants in battle activate instructions for more context-specific battle text.
- Example: `this.add('-activate', pokemon, 'ability: example', '[msg]message1');` will parse to lang key `cobblemon.battle.activate.example.message1`.
### Localization
- Updated translations for:
- French
- Canadian French
- Simplified Chinese
- Ukrainian
- Brazilian Portuguese
- Spanish
- Korean
- Japanese
-22
View File
@@ -1,22 +0,0 @@
# Changelog
## [1.7.3 (January 31st, 2026)](#1-7-3)
### Fixes
- Fixed mounted Pokémon not playing sounds.
- Fixed players failing to join servers randomly.
- Fixed some Pokémon having no stamina for flying.
- Fixed `/pctake` not respecting the actual size of the PC.
### Developer
- Poké Ball GUI textures now respect the ball's namespace, enabling proper texture loading for custom balls from other mods.
### Molang & Datapacks
- Added a `chance` requirement type for Pokémon interactions.
### Localization
- Updated translations for:
- French
- Canadian French
- Korean
- Portuguese
- Simplified Chinese
- Spanish
+1 -1
View File
@@ -55,7 +55,7 @@ dependencies {
// modCompileOnly(libs.flywheelFabric)
// Showdown
modCompileOnly(libs.graal.core)
modCompileOnly(libs.graal)
// Data Storage
modCompileOnly(libs.bundles.mongo)
@@ -11,9 +11,7 @@ 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.api.pokemon.PokemonProperties;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.world.feature.SaccharineTreeFeature;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.tags.BlockTags;
@@ -44,21 +42,7 @@ public abstract class BeeOccupantMixin {
if (cir.getReturnValue() == null) {
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
CompoundTag compoundTag = occupant.entityData().copyTag();
String id = compoundTag.getString("id");
Entity entity = null;
if (id.equals(SaccharineTreeFeature.Companion.getPOKEMON_PLACEHOLD_ID())) {
// Special case for Pokemon stuffed into a beenest upon world gen.
// For technical reasons we cannot create them as full entities during world gen.
// So we look for this special id tag and complete the entity when it attempts to exit a hive.
if (compoundTag.contains("pokemonProperties")) {
String properties = compoundTag.getString("pokemonProperties");
PokemonProperties pokemon = PokemonProperties.Companion.parse(properties);
entity = pokemon.createEntity(level);
}
} else {
entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
}
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
if (entity instanceof PokemonEntity pokemonEntity) {
var state = level.getBlockState(pos);
var newPos = Vec3.ZERO;
@@ -37,16 +37,16 @@ public class ClientPacketListenerMixin {
passengers.add(this.level.getEntity(passenger));
}
Arrays
.stream(pokemon.getOccupiedSeats())
.filter(x -> !passengers.contains(x))
.filter(Objects::nonNull)
.forEach(Entity::stopRiding);
.stream(pokemon.getOccupiedSeats())
.filter(x -> !passengers.contains(x))
.filter(Objects::nonNull)
.forEach(Entity::stopRiding);
var occupiedSeats = Arrays.asList(pokemon.getOccupiedSeats());
passengers.stream()
.filter(x -> !occupiedSeats.contains(x))
.filter(Objects::nonNull)
.forEach(x -> x.startRiding(pokemon, true));
.filter(x -> !occupiedSeats.contains(x))
.filter(Objects::nonNull)
.forEach(x -> x.startRiding(pokemon, true));
ci.cancel();
}
}
@@ -15,8 +15,6 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
import com.cobblemon.mod.common.api.riding.RidingStyle;
import com.cobblemon.mod.common.api.riding.behaviour.types.air.HoverBehaviour;
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;
@@ -61,7 +59,6 @@ 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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -172,32 +169,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
}
}
@Redirect(
method = "getDestroySpeed",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Player;onGround()Z"
)
)
private boolean cobblemon$considerHoverOnGround(Player player) {
// If riding a Hover Mount, return true to bypass the 5x slowdown
if (player.getVehicle() instanceof PokemonEntity vehicle) {
var ridingController = vehicle.getRidingController();
if (ridingController == null) player.onGround();
var activeContext = ridingController.getContext();
if (activeContext == null) player.onGround();
if (activeContext.getStyle() == RidingStyle.AIR &&
activeContext.getBehaviour().equals(HoverBehaviour.Companion.getKEY())) {
return true;
}
}
// Otherwise, return the actual value
return player.onGround();
}
@Inject(
method = "eat",
at = @At(
@@ -101,7 +101,7 @@ public abstract class ServerEntityMixin {
cobblemon$broadcast(new ClientboundUpdateDriverInputPacket(driverInput, entity.getId()));
}
public void cobblemon$broadcast(NetworkPacket<?> packet) {
private void cobblemon$broadcast(NetworkPacket<?> packet) {
if (!(entity.level() instanceof ServerLevel level)) return;
ChunkMap chunkMap = level.getChunkSource().chunkMap;
Int2ObjectMap<?> entityMap = ((ChunkMapAccessor) chunkMap).getEntityMap();
@@ -11,15 +11,11 @@ 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.riding.RidingStyle;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
import com.cobblemon.mod.common.api.stats.CobblemonStats;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -93,32 +89,4 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
return original && !(entity instanceof PokemonEntity);
}
@WrapOperation(method = "checkRidingStatistics", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;getVehicle()Lnet/minecraft/world/entity/Entity;"))
public Entity cobblemon$checkRidingStatistics(ServerPlayer player, Operation<Entity> original, @Local int distance) {
var entity = original.call(player);
if (!(entity instanceof PokemonEntity pokemonEntity)) {
return entity;
}
var ridingController = pokemonEntity.getRidingController();
if (ridingController == null) return entity;
var activeContext = ridingController.getContext();
if (activeContext == null) return entity;
var ridingStyle = activeContext.getStyle();
CobblemonStats.CobblemonStat stat = switch (ridingStyle) {
case RidingStyle.LAND -> CobblemonStats.RIDING_LAND;
case RidingStyle.AIR -> CobblemonStats.RIDING_AIR;
case RidingStyle.LIQUID -> CobblemonStats.RIDING_LIQUID;
default -> null;
};
if (stat != null) {
player.awardStat(CobblemonStats.getStat(stat), distance);
}
return entity;
}
}
@@ -1,26 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.world.item.Item;
import net.minecraft.core.dispenser.DispenseItemBehavior;
import net.minecraft.world.level.block.DispenserBlock;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(DispenserBlock.class)
public interface DispenserBlockAccessor {
@Accessor("DISPENSER_REGISTRY")
static Map<Item, DispenseItemBehavior> getItemBehaviors() {
throw new AssertionError();
}
}
@@ -33,7 +33,7 @@ public class AbstractClientPlayerMixin {
cir.setReturnValue(usageContext.getFovMultiplier());
} else {
// Only modify fov through riding if the pokedex is not open
AbstractClientPlayer player = (AbstractClientPlayer) (Object) this;
LocalPlayer player = (LocalPlayer) (Object) this;
// 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();
@@ -35,7 +35,6 @@ 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 com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts;
import static com.google.common.primitives.Floats.min;
import static net.minecraft.util.Mth.lerp;
@@ -86,13 +85,11 @@ public abstract class MouseHandlerMixin {
CobblemonClient.INSTANCE.getStorage().shiftSelected(false);
ci.cancel();
PartySendBinding.INSTANCE.actioned();
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
} else if (i < 0) {
accumulatedScrollY -= i;
CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
ci.cancel();
PartySendBinding.INSTANCE.actioned();
PartyTutorialToasts.INSTANCE.onHoldKeyScrollSwitchedSlot();
}
}
}
@@ -313,7 +310,7 @@ public abstract class MouseHandlerMixin {
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(), -89.0F, 89.0F));
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);
@@ -14,14 +14,9 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.Pokemon;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalBooleanRef;
import com.llamalad7.mixinextras.sugar.ref.LocalFloatRef;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
@@ -55,8 +50,16 @@ public abstract class EntityMixin {
)
)
public boolean cobblemon$forceOnGroundForStepUp(Entity entity, Operation<Boolean> original) {
if (entity instanceof PokemonEntity vehicle && entity.hasControllingPassenger()) {
return true;
if (entity instanceof PokemonEntity && entity.hasControllingPassenger()) {
BlockPos below = entity.blockPosition().below();
Level level = entity.level();
var blockStateBelow = level.getBlockState(below);
boolean isAirOrLiquid = blockStateBelow.isAir() || !blockStateBelow.getFluidState().isEmpty();
boolean canSupportEntity = blockStateBelow.isFaceSturdy(level, below, Direction.UP);
boolean standingOnSolid = canSupportEntity && !isAirOrLiquid;
if (standingOnSolid) {
return true;
}
}
return original.call(entity);
}
@@ -94,61 +97,4 @@ public abstract class EntityMixin {
cir.setReturnValue(customEyePos);
}
@WrapOperation(
method = "push(Lnet/minecraft/world/entity/Entity;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;push(DDD)V", ordinal = 0)
)
public void cobblemon$customPusherLogic(Entity pusher, double x, double y, double z,
Operation<Void> original,
@Local(argsOnly = true) Entity pushee,
@Local(name = "e") double e, @Local(name = "d") double d,
@Share("pusherIsPlayerOrPokemon") LocalBooleanRef pusherIsPlayerOrPokemon,
@Share("pusheeIsPlayerOrPokemon") LocalBooleanRef pusheeIsPlayerOrPokemon,
@Share("pusheeReceivedForce")LocalFloatRef pusheeReceivedForce) {
pusherIsPlayerOrPokemon.set(pusher instanceof PokemonEntity || pusher instanceof Player);
pusheeIsPlayerOrPokemon.set(pushee instanceof PokemonEntity || pushee instanceof Player);
if (!pusheeIsPlayerOrPokemon.get() || !pusherIsPlayerOrPokemon.get()) {
original.call(pusher, x, y, z);
return;
}
/**********************************************
* Custom portion of the code:
* Handle collisions with weight in mind. Use
* the weight value of pokemon to determine
* which side gets what portion of the total
* force.
*********************************************/
// Weights in hectograms
// Check to see if the pusher or pushee is a player. 200ish pounds. Steve's like a 6'6 miner
var pusherWeight = pusher instanceof PokemonEntity pusherPokemon ? pusherPokemon.getPokemon().getSpecies().getWeight() : 900F;
var pusheeWeight = pushee instanceof PokemonEntity pusheePokemon ? pusheePokemon.getPokemon().getSpecies().getWeight() : 900F;
// Calculate the portion of force received for both entities. Bigger receives less from the
// collision than the smaller one.
var totalWeight = pusherWeight + pusheeWeight;
var pusherReceivedForce = pusheeWeight / totalWeight * 2F;
pusheeReceivedForce.set((pusherWeight / totalWeight) * 2F);
original.call(pusher, -d * pusherReceivedForce, 0.0, -e * pusherReceivedForce);
}
@WrapOperation(
method = "push(Lnet/minecraft/world/entity/Entity;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Entity;push(DDD)V", ordinal = 1)
)
public void cobblemon$customPusheeLogic(Entity pusher, double x, double y, double z, Operation<Void> original,
@Local(name = "e") double e, @Local(name = "d") double d,
@Share("pusherIsPlayerOrPokemon") LocalBooleanRef pusherIsPlayerOrPokemon,
@Share("pusheeIsPlayerOrPokemon") LocalBooleanRef pusheeIsPlayerOrPokemon,
@Share("pusheeReceivedForce")LocalFloatRef pusheeReceivedForce) {
if (!pusheeIsPlayerOrPokemon.get() || !pusherIsPlayerOrPokemon.get()) {
original.call(pusher, x, y, z);
return;
}
original.call(pusher, d * pusheeReceivedForce.get(), 0.0, e * pusheeReceivedForce.get());
}
}
@@ -42,8 +42,8 @@ import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningZoneGenerator
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
import com.cobblemon.mod.common.api.starter.StarterHandler
import com.cobblemon.mod.common.api.stats.CobblemonStats
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
@@ -65,14 +65,10 @@ import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataMongoBacken
import com.cobblemon.mod.common.api.storage.player.factory.CachedPlayerDataStoreFactory
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.ShowdownThread
import com.cobblemon.mod.common.battles.*
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.block.dispenser.DispenserBehaviorRegistry
import com.cobblemon.mod.common.block.DispenserBehaviorRegistry
import com.cobblemon.mod.common.client.CobblemonPack
import com.cobblemon.mod.common.command.argument.*
import com.cobblemon.mod.common.config.CobblemonConfig
@@ -81,8 +77,8 @@ import com.cobblemon.mod.common.config.constraint.IntConstraint
import com.cobblemon.mod.common.config.starter.StarterConfig
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.events.AdvancementHandler
import com.cobblemon.mod.common.events.CallbackHandler
import com.cobblemon.mod.common.events.EntityCallbackHandler
import com.cobblemon.mod.common.events.CallbackHandler
import com.cobblemon.mod.common.events.PokedexHandler
import com.cobblemon.mod.common.events.ServerTickHandler
import com.cobblemon.mod.common.events.StatHandler
@@ -99,23 +95,11 @@ import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatu
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatureProvider
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
import com.cobblemon.mod.common.pokemon.properties.FreezeFrameProperty
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.LabelProperty
import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.*
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.ifDedicatedServer
import com.cobblemon.mod.common.util.isLaterVersion
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.requestWallpapers
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
@@ -123,17 +107,6 @@ import com.mongodb.ConnectionString
import com.mongodb.MongoClientSettings
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoClients
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.UUID
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import net.minecraft.client.Minecraft
import net.minecraft.commands.synchronization.SingletonArgumentInfo
import net.minecraft.resources.ResourceKey
@@ -146,6 +119,17 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.storage.LevelResource
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
object Cobblemon {
const val MODID = CobblemonBuildDetails.MOD_ID
@@ -186,7 +170,7 @@ object Cobblemon {
val statistics: CobblemonStats = CobblemonStats
@JvmStatic
val builtinPacks = listOf(
val builtinPacks = listOf<CobblemonPack>(
CobblemonPack(id = "adorncompatibility", name = "Adorn Compatibility", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.ALWAYS_ENABLED, neededMods = setOf("adorn")),
CobblemonPack(id = "gyaradosjump", name = "Gyarados Jump Patterns", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED),
CobblemonPack(id = "regionbiasforms", name = "Region Bias Forms", packType = PackType.CLIENT_RESOURCES, activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED),
@@ -222,7 +206,6 @@ object Cobblemon {
implementation.registerEntityDataSerializers()
implementation.registerCriteria()
implementation.registerEntitySubPredicates()
implementation.registerMobEffects()
DispenserBehaviorRegistry.registerDispenserBehaviors()
DropEntry.register("command", CommandDropEntry::class.java)
@@ -336,7 +319,7 @@ object Cobblemon {
CustomPokemonProperty.register(UncatchableProperty)
CustomPokemonProperty.register(BattleCloneProperty)
CustomPokemonProperty.register(LabelProperty)
CustomPokemonProperty.register(PokemonFlagProperty)
CustomPokemonProperty.register(HiddenAbilityPropertyType)
CustomPokemonProperty.register(AspectPropertyType)
CustomPokemonProperty.register(UnaspectPropertyType)
@@ -472,7 +455,7 @@ object Cobblemon {
server()?.getLevel(dimension)
} else {
val mc = Minecraft.getInstance()
mc.singleplayerServer?.getLevel(dimension) ?: mc.level
return mc.singleplayerServer?.getLevel(dimension) ?: mc.level
}
}
@@ -28,8 +28,6 @@ object CobblemonActivities {
@JvmField
val POKEMON_HERD = register(Activity("pokemon_herd"))
@JvmField
val POKEMON_BOIDS = register(Activity("pokemon_boid"))
@JvmField
val POKEMON_POLLINATION = register(Activity("pokemon_pollination"))
@JvmStatic
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.block.*
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
import com.cobblemon.mod.common.block.LecternBlock
@@ -42,11 +41,11 @@ import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.properties.BlockSetType
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.level.block.state.properties.BlockStateProperties.LIT
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument
import net.minecraft.world.level.block.state.properties.WoodType
import net.minecraft.world.level.material.MapColor
import net.minecraft.world.level.material.PushReaction
import net.minecraft.world.phys.shapes.Shapes
@Suppress("SameParameterValue", "HasPlatformType", "MemberVisibilityCanBePrivate", "unused")
object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<Block>>, Block>() {
@@ -216,7 +215,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_WALL_HANGING_SIGN = this.create("saccharine_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
@@ -244,9 +243,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).mapColor(MapColor.PLANT).ignitedByLava().noCollission().instabreak().sound(CobblemonSounds.REVIVAL_HERB_SOUNDS)))
@JvmField
val POKE_CAKE = this.create("poke_cake", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(BlockStateProperties.LIT)) 3 else 0 }, false))
val POKE_CAKE = this.create("poke_cake", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(LIT)) 3 else 0 }, false))
@JvmField
val POKE_SNACK = this.create("poke_snack", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(BlockStateProperties.LIT)) 3 else 0 }, true))
val POKE_SNACK = this.create("poke_snack", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(LIT)) 3 else 0 }, true))
@JvmField
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@@ -478,99 +477,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val GIMMIGHOUL_CHEST = create("gimmighoul_chest", GildedChestBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.CHEST).noOcclusion().sound(CobblemonSounds.GILDED_CHEST_SOUNDS), GildedChestBlock.Type.FAKE))
@JvmField
val WHITE_PLAQUE = create("white_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val LIGHT_GRAY_PLAQUE = create("light_gray_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val GRAY_PLAQUE = create("gray_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val BLACK_PLAQUE = create("black_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val BROWN_PLAQUE = create("brown_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val RED_PLAQUE = create("red_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val ORANGE_PLAQUE = create("orange_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val YELLOW_PLAQUE = create("yellow_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val LIME_PLAQUE = create("lime_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val GREEN_PLAQUE = create("green_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val CYAN_PLAQUE = create("cyan_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val LIGHT_BLUE_PLAQUE = create("light_blue_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val BLUE_PLAQUE = create("blue_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val PURPLE_PLAQUE = create("purple_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val MAGENTA_PLAQUE = create("magenta_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val PINK_PLAQUE = create("pink_plaque", PlaqueBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.METAL).noOcclusion().pushReaction(PushReaction.DESTROY).strength(5.0F)))
@JvmField
val CLEANSE_TAG = create("cleanse_tag", WallAttachedStackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion().noCollission(), WallAttachedStackableItemBlock.WallStackableItemBlockType.TAG))
@JvmField
val SPELL_TAG = create("spell_tag", WallAttachedStackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).mapColor(MapColor.NONE).pushReaction(PushReaction.DESTROY).noOcclusion().noCollission(), WallAttachedStackableItemBlock.WallStackableItemBlockType.TAG))
@JvmField
val BLUNDER_POLICY = create("blunder_policy", WallAttachedDirectionalShapeBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion().noCollission(), 14, 12, 1))
@JvmField
val WEAKNESS_POLICY = create("weakness_policy", WallAttachedDirectionalShapeBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion().noCollission(), 14, 12, 1))
@JvmField
val FULL_HEAL = create("full_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@JvmField
val ANTIDOTE = create("antidote", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@JvmField
val AWAKENING = create("awakening", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@JvmField
val BURN_HEAL = create("burn_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@JvmField
val ICE_HEAL = create("ice_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@JvmField
val PARALYZE_HEAL = create("paralyze_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@JvmField
val ETHER = create("ether", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.ETHER))
@JvmField
val MAX_ETHER = create("max_ether", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.ETHER))
@JvmField
val ELIXIR = create("elixir", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.ETHER))
@JvmField
val MAX_ELIXIR = create("max_elixir", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.ETHER))
@JvmField
val POTION = create("potion", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.POTION))
@JvmField
val SUPER_POTION = create("super_potion", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.POTION))
@JvmField
val HYPER_POTION = create("hyper_potion", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.POTION))
@JvmField
val MAX_POTION = create("max_potion", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.MAX_POTION))
@JvmField
val FULL_RESTORE = create("full_restore", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.MAX_POTION))
@JvmField
val DIRE_HIT = create("dire_hit", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val GUARD_SPEC = create("guard_spec", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val X_ACCURACY = create("x_${Stats.ACCURACY.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val X_ATTACK = create("x_${Stats.ATTACK.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val X_DEFENSE = create("x_${Stats.DEFENCE.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val X_SP_ATK = create("x_${Stats.SPECIAL_ATTACK.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val X_SP_DEF = create("x_${Stats.SPECIAL_DEFENCE.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val X_SPEED = create("x_${Stats.SPEED.identifier.path}", StackableItemBlock(BlockBehaviour.Properties.of().sound(SoundType.CANDLE).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.BATTLE_ITEM))
@JvmField
val MONITOR = create("monitor", MonitorBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).lightLevel { if (it.getValue(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 13 else 0 }))
@JvmField
@@ -117,11 +117,6 @@ interface CobblemonImplementation {
fun registerEntitySubPredicates()
/**
* TODO
*/
fun registerMobEffects()
/**
* Add a feature to the current platform implementation.
@@ -507,23 +507,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val SCROLL_OF_DARKNESS = noSettingsItem("scroll_of_darkness")
@JvmField val SCROLL_OF_WATERS = noSettingsItem("scroll_of_waters")
@JvmField val WHITE_PLAQUE = blockItem("white_plaque", CobblemonBlocks.WHITE_PLAQUE)
@JvmField val LIGHT_GRAY_PLAQUE = blockItem("light_gray_plaque", CobblemonBlocks.LIGHT_GRAY_PLAQUE)
@JvmField val GRAY_PLAQUE = blockItem("gray_plaque", CobblemonBlocks.GRAY_PLAQUE)
@JvmField val BLACK_PLAQUE = blockItem("black_plaque", CobblemonBlocks.BLACK_PLAQUE)
@JvmField val BROWN_PLAQUE = blockItem("brown_plaque", CobblemonBlocks.BROWN_PLAQUE)
@JvmField val RED_PLAQUE = blockItem("red_plaque", CobblemonBlocks.RED_PLAQUE)
@JvmField val ORANGE_PLAQUE = blockItem("orange_plaque", CobblemonBlocks.ORANGE_PLAQUE)
@JvmField val YELLOW_PLAQUE = blockItem("yellow_plaque", CobblemonBlocks.YELLOW_PLAQUE)
@JvmField val LIME_PLAQUE = blockItem("lime_plaque", CobblemonBlocks.LIME_PLAQUE)
@JvmField val GREEN_PLAQUE = blockItem("green_plaque", CobblemonBlocks.GREEN_PLAQUE)
@JvmField val CYAN_PLAQUE = blockItem("cyan_plaque", CobblemonBlocks.CYAN_PLAQUE)
@JvmField val LIGHT_BLUE_PLAQUE = blockItem("light_blue_plaque", CobblemonBlocks.LIGHT_BLUE_PLAQUE)
@JvmField val BLUE_PLAQUE = blockItem("blue_plaque", CobblemonBlocks.BLUE_PLAQUE)
@JvmField val PURPLE_PLAQUE = blockItem("purple_plaque", CobblemonBlocks.PURPLE_PLAQUE)
@JvmField val MAGENTA_PLAQUE = blockItem("magenta_plaque", CobblemonBlocks.MAGENTA_PLAQUE)
@JvmField val PINK_PLAQUE = blockItem("pink_plaque", CobblemonBlocks.PINK_PLAQUE)
private val berries = mutableMapOf<ResourceLocation, BerryItem>()
// Plants
@JvmField val CHERI_BERRY = berryItem("cheri", StatusCuringBerryItem(CobblemonBlocks.CHERI_BERRY, Statuses.PARALYSIS))
@@ -716,15 +699,15 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val MOOMOO_MILK = create("moomoo_milk", MoomooMilk(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
@JvmField
val POTION = create("potion", PotionItem(PotionType.POTION, CobblemonBlocks.POTION))
val POTION = create("potion", PotionItem(PotionType.POTION))
@JvmField
val SUPER_POTION = create("super_potion", PotionItem(PotionType.SUPER_POTION, CobblemonBlocks.SUPER_POTION))
val SUPER_POTION = create("super_potion", PotionItem(PotionType.SUPER_POTION))
@JvmField
val HYPER_POTION = create("hyper_potion", PotionItem(PotionType.HYPER_POTION, CobblemonBlocks.HYPER_POTION))
val HYPER_POTION = create("hyper_potion", PotionItem(PotionType.HYPER_POTION))
@JvmField
val MAX_POTION = create("max_potion", PotionItem(PotionType.MAX_POTION, CobblemonBlocks.MAX_POTION))
val MAX_POTION = create("max_potion", PotionItem(PotionType.MAX_POTION))
@JvmField
val FULL_RESTORE = create("full_restore", PotionItem(PotionType.FULL_RESTORE, CobblemonBlocks.FULL_RESTORE))
val FULL_RESTORE = create("full_restore", PotionItem(PotionType.FULL_RESTORE))
@JvmField
val HEAL_POWDER = create("heal_powder", HealPowderItem())
@@ -809,27 +792,28 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SERIOUS_MINT = mintItem("serious_mint", MintItem(Natures.SERIOUS))
@JvmField val X_ACCURACY = create("x_${Stats.ACCURACY.identifier.path}", XStatItem(Stats.ACCURACY, block = CobblemonBlocks.X_ACCURACY))
@JvmField val X_ATTACK = create("x_${Stats.ATTACK.identifier.path}", XStatItem(Stats.ATTACK, block = CobblemonBlocks.X_ATTACK))
@JvmField val X_DEFENSE = create("x_${Stats.DEFENCE.identifier.path}", XStatItem(Stats.DEFENCE, block = CobblemonBlocks.X_DEFENSE))
@JvmField val X_SP_ATK = create("x_${Stats.SPECIAL_ATTACK.identifier.path}", XStatItem(Stats.SPECIAL_ATTACK, block = CobblemonBlocks.X_SP_ATK))
@JvmField val X_SP_DEF = create("x_${Stats.SPECIAL_DEFENCE.identifier.path}", XStatItem(Stats.SPECIAL_DEFENCE, block = CobblemonBlocks.X_SP_DEF))
@JvmField val X_SPEED = create("x_${Stats.SPEED.identifier.path}", XStatItem(Stats.SPEED, block = CobblemonBlocks.X_SPEED))
@JvmField val X_ACCURACY = create("x_${Stats.ACCURACY.identifier.path}", XStatItem(Stats.ACCURACY))
@JvmField val X_ATTACK = create("x_${Stats.ATTACK.identifier.path}", XStatItem(Stats.ATTACK))
@JvmField val X_DEFENSE = create("x_${Stats.DEFENCE.identifier.path}", XStatItem(Stats.DEFENCE))
@JvmField val X_SP_ATK = create("x_${Stats.SPECIAL_ATTACK.identifier.path}", XStatItem(Stats.SPECIAL_ATTACK))
@JvmField val X_SP_DEF = create("x_${Stats.SPECIAL_DEFENCE.identifier.path}", XStatItem(Stats.SPECIAL_DEFENCE))
@JvmField val X_SPEED = create("x_${Stats.SPEED.identifier.path}", XStatItem(Stats.SPEED))
@JvmField val DIRE_HIT = create("dire_hit", DireHitItem(CobblemonBlocks.DIRE_HIT))
@JvmField val GUARD_SPEC = create("guard_spec", GuardSpecItem(CobblemonBlocks.GUARD_SPEC))
@JvmField val DIRE_HIT = create("dire_hit", DireHitItem())
@JvmField val GUARD_SPEC = create("guard_spec", GuardSpecItem())
@JvmField val FULL_HEAL = create("full_heal", StatusCureItem("item.cobblemon.full_heal", block = CobblemonBlocks.FULL_HEAL))
@JvmField val ANTIDOTE = create("antidote", StatusCureItem("item.cobblemon.antidote", Statuses.POISON, Statuses.POISON_BADLY, block = CobblemonBlocks.ANTIDOTE))
@JvmField val AWAKENING = create("awakening", StatusCureItem("item.cobblemon.awakening", Statuses.SLEEP, block = CobblemonBlocks.AWAKENING))
@JvmField val BURN_HEAL = create("burn_heal", StatusCureItem("item.cobblemon.burn_heal", Statuses.BURN, block = CobblemonBlocks.BURN_HEAL))
@JvmField val ICE_HEAL = create("ice_heal", StatusCureItem("item.cobblemon.ice_heal", Statuses.FROZEN, block = CobblemonBlocks.ICE_HEAL))
@JvmField val PARALYZE_HEAL = create("paralyze_heal", StatusCureItem("item.cobblemon.paralyze_heal", Statuses.PARALYSIS, block = CobblemonBlocks.PARALYZE_HEAL))
@JvmField val BURN_HEAL = create("burn_heal", StatusCureItem("item.cobblemon.burn_heal", Statuses.BURN))
@JvmField val PARALYZE_HEAL = create("paralyze_heal", StatusCureItem("item.cobblemon.paralyze_heal", Statuses.PARALYSIS))
@JvmField val ICE_HEAL = create("ice_heal", StatusCureItem("item.cobblemon.ice_heal", Statuses.FROZEN))
@JvmField val ANTIDOTE = create("antidote", StatusCureItem("item.cobblemon.antidote", Statuses.POISON, Statuses.POISON_BADLY))
@JvmField val AWAKENING = create("awakening", StatusCureItem("item.cobblemon.awakening", Statuses.SLEEP))
@JvmField val ETHER = create("ether", EtherItem(max = false, CobblemonBlocks.ETHER))
@JvmField val MAX_ETHER = create("max_ether", EtherItem(max = true, CobblemonBlocks.MAX_ETHER))
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false, CobblemonBlocks.ELIXIR))
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true, CobblemonBlocks.MAX_ELIXIR))
@JvmField val FULL_HEAL = create("full_heal", StatusCureItem("item.cobblemon.full_heal"))
@JvmField val ETHER = create("ether", EtherItem(max = false))
@JvmField val MAX_ETHER = create("max_ether", EtherItem(max = true))
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false))
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true))
@JvmField
val ABILITY_CAPSULE = this.create("ability_capsule", AbilityChangeItem(AbilityChanger.COMMON_ABILITY))
@@ -938,7 +922,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val BLACK_SLUDGE = heldItem("black_sludge")
@JvmField
val BLUNDER_POLICY = itemNameBlockItem("blunder_policy", CobblemonBlocks.BLUNDER_POLICY)
val BLUNDER_POLICY = heldItem("blunder_policy")
@JvmField
val CELL_BATTERY = heldItem("cell_battery")
@JvmField
@@ -946,7 +930,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val CHOICE_SCARF = heldItem("choice_scarf")
@JvmField
val CLEANSE_TAG = itemNameBlockItem("cleanse_tag", CobblemonBlocks.CLEANSE_TAG)
val CLEANSE_TAG = heldItem("cleanse_tag")
@JvmField
val CLEAR_AMULET = heldItem("clear_amulet")
@JvmField
@@ -1054,7 +1038,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SOFT_SAND = heldItem("soft_sand")
@JvmField
val SPELL_TAG = itemNameBlockItem("spell_tag", CobblemonBlocks.SPELL_TAG)
val SPELL_TAG = heldItem("spell_tag")
@JvmField
val SMOKE_BALL = heldItem("smoke_ball")
@JvmField
@@ -1072,7 +1056,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val UTILITY_UMBRELLA = heldItem("utility_umbrella")
@JvmField
val WEAKNESS_POLICY = itemNameBlockItem("weakness_policy", CobblemonBlocks.WEAKNESS_POLICY)
val WEAKNESS_POLICY = heldItem("weakness_policy")
@JvmField
val WIDE_LENS = heldItem("wide_lens")
@JvmField
@@ -1569,7 +1553,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
}
}
)
private fun heldItem(name: String, item: Item, remappedName: String? = null) = create(
name = name,
entry = item.also {
@@ -21,7 +21,6 @@ import net.minecraft.core.UUIDUtil
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import java.util.*
import net.minecraft.world.entity.player.Player
object CobblemonMemories {
val memories = mutableMapOf<String, MemoryModuleType<*>>()
@@ -93,9 +92,6 @@ object CobblemonMemories {
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")
/** Is the nearest player holding a diamond for debugging purposes? */
@JvmField
val DIAMOND_DEBUGGER = register<Player>("diamond_debugger")
@JvmStatic
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.cooking.effects.CleanseAllEffect
import com.cobblemon.mod.common.api.cooking.effects.CleanseNegativeEffect
import com.cobblemon.mod.common.api.cooking.effects.MentalRestorationEffect
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.world.effect.MobEffect
object CobblemonMobEffects : PlatformRegistry<Registry<MobEffect>, ResourceKey<Registry<MobEffect>>, MobEffect>() {
override val registry: Registry<MobEffect> = BuiltInRegistries.MOB_EFFECT
override val resourceKey: ResourceKey<Registry<MobEffect>> = Registries.MOB_EFFECT
@JvmField
val CLEANSE_NEGATIVE = create("cleanse_negative", CleanseNegativeEffect())
@JvmField
val MENTAL_RESTORATION = create("mental_restoration", MentalRestorationEffect())
@JvmField
val CLEANSE_ALL = create("cleanse_all", CleanseAllEffect())
}
@@ -23,7 +23,6 @@ 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.debug.OpenRidingStatsDebugGUIHandler
import com.cobblemon.mod.common.client.net.debug.S2CUpdateObsAvoidHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
@@ -81,7 +80,6 @@ import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallba
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.cooking.ToggleCookingPotLidPacket
import com.cobblemon.mod.common.net.messages.client.data.*
import com.cobblemon.mod.common.net.messages.client.debug.ClientboundUpdateObsAvoidPacket
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
@@ -142,7 +140,13 @@ 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
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
@@ -185,7 +189,6 @@ import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRide
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
import com.cobblemon.mod.common.net.messages.server.storage.party.PartyTutorialPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
@@ -222,7 +225,6 @@ import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandl
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.ServerboundUpdateOrientationHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.PartyTutorialPacketHandler
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
@@ -255,11 +257,7 @@ import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import com.cobblemon.mod.common.mixin.accessor.ChunkMapAccessor
import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor
/**
* Registers Cobblemon network packets.
@@ -282,19 +280,6 @@ object CobblemonNetwork {
fun sendToAllPlayers(packet: NetworkPacket<*>) = sendPacketToPlayers(server()!!.playerList.players, packet)
@JvmStatic
fun sendPacketToPlayers(players: Iterable<ServerPlayer>, packet: NetworkPacket<*>) = players.forEach { sendPacketToPlayer(it, packet) }
fun sendPacketToTrackingPlayers(entity: Entity, packet: NetworkPacket<*>) {
val level = entity.level() as? ServerLevel ?: return
val chunkMap = level.chunkSource.chunkMap
val entityTracker = (chunkMap as ChunkMapAccessor).entityMap[entity.id]
if (entityTracker is TrackedEntityAccessor) {
entityTracker.seenBy.forEach { connection ->
sendPacketToPlayer(connection.player, packet)
}
}
}
val s2cPayloads = generateS2CPacketInfoList()
val c2sPayloads = generateC2SPacketInfoList()
@@ -416,7 +401,6 @@ object CobblemonNetwork {
// Data registries
list.add(PacketRegisterInfo(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(CobblemonMechanicsSyncPacket.ID, CobblemonMechanicsSyncPacket::decode, CobblemonMechanicsSyncHandler))
list.add(PacketRegisterInfo(PokemonInteractionsSyncPacket.ID, PokemonInteractionsSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
@@ -502,7 +486,6 @@ object CobblemonNetwork {
// Debug / cheats
list.add(PacketRegisterInfo(CalculateSeatPositionsPacket.ID, CalculateSeatPositionsPacket::decode, CalculateSeatPositionsHandler))
list.add(PacketRegisterInfo(ClientboundUpdateObsAvoidPacket.ID, ClientboundUpdateObsAvoidPacket::decode, S2CUpdateObsAvoidHandler))
// Riding
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
@@ -545,7 +528,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(ReleasePCPokemonPacket.ID, ReleasePCPokemonPacket::decode, ReleasePCPokemonHandler))
list.add(PacketRegisterInfo(UnlinkPlayerFromPCPacket.ID, UnlinkPlayerFromPCPacket::decode, UnlinkPlayerFromPCHandler))
list.add(PacketRegisterInfo(RequestRenamePCBoxPacket.ID, RequestRenamePCBoxPacket::decode, RequestRenamePCBoxHandler))
list.add(PacketRegisterInfo(RequestRenamePCBoxPacket.Companion.ID, RequestRenamePCBoxPacket.Companion::decode, RequestRenamePCBoxHandler))
list.add(PacketRegisterInfo(PCBoxWallpapersPacket.ID, PCBoxWallpapersPacket::decode, PCBoxWallpapersHandler))
list.add(PacketRegisterInfo(RequestChangePCBoxWallpaperPacket.ID, RequestChangePCBoxWallpaperPacket::decode, RequestChangePCBoxWallpaperHandler))
list.add(PacketRegisterInfo(MarkPCBoxWallpapersSeenPacket.ID, MarkPCBoxWallpapersSeenPacket::decode, MarkPCBoxWallpapersSeenHandler))
@@ -603,9 +586,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler))
list.add(PacketRegisterInfo(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler))
//Party move tutorial toasts packets
list.add(PacketRegisterInfo(PartyTutorialPacket.ID, PartyTutorialPacket::decode, PartyTutorialPacketHandler))
// Dialogue packets
list.add(PacketRegisterInfo(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler))
list.add(PacketRegisterInfo(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler))
@@ -49,9 +49,6 @@ object CobblemonSensors {
@JvmField
val NEARBY_SWEET_BERRY_BUSH = register("nearby_sweet_berry_bush", ::SweetBerryBushSensor)
@JvmField
val PLAYER_DEBUGGING = register("player_debugging", ::PlayerDebuggingSensor)
@JvmField
val POKEMON_NEARBY_WANTED_ITEM = register("pokemon_nearby_wanted_item", ::PokemonItemSensor)
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.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.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.WakeUpTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class BoidsTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
if (entity !is PokemonEntity) {
return null
}
behaviourConfigurationContext.addMemories(CobblemonMemories.POKEMON_DROWSY, CobblemonMemories.POKEMON_SLEEPING)
behaviourConfigurationContext.addSensors(CobblemonSensors.POKEMON_DROWSY)
return WrapperLivingEntityTask(WakeUpTask.create(), PokemonEntity::class.java)
}
}
@@ -1,44 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.DefendOwnerTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class DefendOwnerTaskConfig : SingleTaskConfig {
override fun getVariables(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): List<MoLangConfigVariable> {
return emptyList()
}
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(
MemoryModuleType.ATTACK_TARGET,
CobblemonMemories.NEAREST_VISIBLE_ATTACKER,
)
return WrapperLivingEntityTask(
DefendOwnerTask.create(),
PokemonEntity::class.java
)
}
}
@@ -1,44 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.BoidsMoveControl
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
class SwitchFromBoidTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(CobblemonMemories.DIAMOND_DEBUGGER)
return BehaviorBuilder.create {
it.group(
it.absent(CobblemonMemories.DIAMOND_DEBUGGER)
).apply(it) { _ ->
Trigger { world, entity, time ->
if(entity !is PokemonEntity) return@Trigger false
if (entity.moveControl !is PokemonMoveControl) {
entity.moveControl = PokemonMoveControl(entity)
}
entity.brain.updateActivityFromSchedule(world.dayTime, world.gameTime)
return@Trigger true
}
}
}
}
}
@@ -1,62 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonActivities
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.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.BoidsMoveControl
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.player.Player
class SwitchToBoidTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(CobblemonMemories.DIAMOND_DEBUGGER)
behaviourConfigurationContext.addSensors(CobblemonSensors.PLAYER_DEBUGGING)
return BehaviorBuilder.create {
it.group(
it.present(CobblemonMemories.DIAMOND_DEBUGGER)
).apply(it) { _ ->
Trigger { world, entity, time ->
if(entity !is PokemonEntity) return@Trigger false
val player = entity.brain.getMemory(CobblemonMemories.DIAMOND_DEBUGGER).orElse(null)
if (entity.moveControl !is BoidsMoveControl && player is LivingEntity) {
entity.moveControl = BoidsMoveControl(entity, player)
} else {
return@Trigger false
}
entity.brain.setActiveActivityIfPossible(CobblemonActivities.POKEMON_BOIDS)
// SpawnSnowstormEntityParticlePacket(
// cobblemonResource("evo_particles"),
// entity.id,
// listOf("shiny_particles", "middle")).sendToPlayersAround(
// entity.x,
// entity.y,
// entity.z,
// 64.0,
// entity.level().dimension()
// )
return@Trigger true
}
}
}
}
}
@@ -105,7 +105,6 @@ interface TaskConfig {
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
cobblemonResource("manage_flight_in_battle") to ManageFlightInBattleTaskConfig::class.java,
cobblemonResource("attack_hostile_mobs") to AttackHostileMobsTaskConfig::class.java,
cobblemonResource("defend_owner") to DefendOwnerTaskConfig::class.java,
cobblemonResource("move_to_sweet_berry_bush") to MoveToSweetBerryBushTaskConfig::class.java,
cobblemonResource("stop_moving_to_sweet_berry_bush") to StopTryingToReachSweetBerryBushTaskConfig::class.java,
cobblemonResource("harvest_sweet_berry_bush") to HarvestSweetBerryBushTaskConfig::class.java,
@@ -124,8 +123,6 @@ interface TaskConfig {
cobblemonResource("target_entity") to TargetEntityTaskConfig::class.java,
cobblemonResource("memory_aspect") to MemoryAspectTaskConfig::class.java,
cobblemonResource("activity_change") to ActivityChangeTaskConfig::class.java,
cobblemonResource("switch_from_boid") to SwitchFromBoidTaskConfig::class.java,
cobblemonResource("switch_to_boid") to SwitchToBoidTaskConfig::class.java,
)
}
@@ -17,7 +17,6 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangV
import com.cobblemon.mod.common.entity.OmniPathingEntity
import com.cobblemon.mod.common.entity.ai.CobblemonRandomSurfacePos
import com.cobblemon.mod.common.entity.ai.CobblemonWalkTarget
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.mainThreadRuntime
import com.cobblemon.mod.common.util.resolveFloat
@@ -185,12 +184,6 @@ class WanderTaskConfig : SingleTaskConfig {
if (targetVec == null) continue
// Ignore pathing targets outside of the pasture zone if the pokemon is pastured.
val tethering = (entity as? PokemonEntity)?.tethering
if (tethering?.canRoamTo(BlockPos.containing(targetVec)) == false) {
continue
}
pos = applyHeightConstraints(
pos = BlockPos.containing(targetVec),
minimumHeight = minimumHeight,
@@ -22,21 +22,18 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
import com.cobblemon.mod.common.api.events.battles.BattleFleeAttemptEvent
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.pokemon.stats.BattleEvSource
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.white
import com.cobblemon.mod.common.api.text.yellow
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
import com.cobblemon.mod.common.battles.BattleCaptureAction
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.FleeAttemptActionResponse
import com.cobblemon.mod.common.battles.ForfeitActionResponse
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
@@ -51,9 +48,7 @@ import com.cobblemon.mod.common.entity.npc.NPCBattleActor
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
import com.cobblemon.mod.common.pokemon.requirements.DefeatRequirement
@@ -142,9 +137,6 @@ open class PokemonBattle(
val captureActions = mutableListOf<BattleCaptureAction>()
val majorBattleActions = hashMapOf<UUID, BattleMessage>()
/** Monotonically increasing counter to track faint ordering within this battle. */
var faintCounter = 0
val minorBattleActions = hashMapOf<UUID, BattleMessage>()
val contextManager = ContextManager()
@@ -252,23 +244,12 @@ open class PokemonBattle(
fun end() {
ended = true
val awardToFainted = Cobblemon.config.awardExperienceToFaintedPokemon
val awardOnLoss = Cobblemon.config.awardExperienceOnBattleLoss
this.actors.forEach { actor ->
val faintedPokemons = actor.pokemonList.filter { it.health <= 0 }
actor.getSide().getOppositeSide().actors.forEach { opponent ->
val opponentPokemons = if (awardToFainted) opponent.pokemonList else opponent.pokemonList.filter { it.health > 0 }
val opponentNonFaintedPokemons = opponent.pokemonList.filter { it.health > 0 }
faintedPokemons.forEach { faintedPokemon ->
for (opponentPokemon in opponentPokemons) {
// Faint-order check: if awarding XP to fainted pokemon, only award for enemies that fainted before this pokemon did
if (awardToFainted) {
val enemyFaintedAt = faintedPokemon.faintedAt ?: continue
val opponentFaintedAt = opponentPokemon.faintedAt
if (opponentFaintedAt != null && opponentFaintedAt <= enemyFaintedAt) {
continue
}
}
for (opponentPokemon in opponentNonFaintedPokemons) {
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
val pokemon = opponentPokemon.effectedPokemon
if (facedFainted) {
@@ -289,8 +270,7 @@ open class PokemonBattle(
else -> continue
}
val experience = Cobblemon.experienceCalculator.calculate(opponentPokemon, faintedPokemon, multiplier)
val enemyTeamWiped = actor.pokemonList.all { it.health <= 0 }
if (experience > 0 && (enemyTeamWiped || awardOnLoss)) {
if (experience > 0 && actor.pokemonList.all { it.health <= 0 }) {
opponent.awardExperience(opponentPokemon, experience)
}
Cobblemon.evYieldCalculator.calculate(opponentPokemon, faintedPokemon).forEach { (stat, amount) ->
@@ -324,8 +304,7 @@ open class PokemonBattle(
.forEach{it.pokemon.heal()}
actors.forEach { actor ->
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.postBattlePokemonOperations.forEach { it(battlePokemon) }
battlePokemon.entity?.let { entity -> battlePokemon.postBattleEntityOperations.forEach { it(entity) } }
battlePokemon.entity?.let { entity -> battlePokemon.postBattleEntityOperation(entity) }
if (battlePokemon.effectedPokemon.entity != null
&& battlePokemon.effectedPokemon.entity?.beamMode == 0
&& battlePokemon.effectedPokemon.entity?.platform != PlatformType.NONE) {
@@ -519,13 +498,12 @@ open class PokemonBattle(
}
fun stop() {
writeShowdownAction(">forcetie") // This will terminate the Showdown connection
end()
writeShowdownAction(">forcetie") // This will terminate the Showdown connection
}
fun checkForInputDispatch() {
if (checkForfeit()) return // ignore actors that are still choosing, their choices don't matter anymore
if (checkFleeAttempt()) return
val readyToInput = (actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose })
if (readyToInput && captureActions.isEmpty()) {
actors.filter { it.responses.isNotEmpty() }.forEach { it.writeShowdownResponse() }
@@ -533,20 +511,6 @@ open class PokemonBattle(
}
}
private fun checkFleeAttempt(): Boolean {
val runner = actors.find { it.responses.any { it is FleeAttemptActionResponse } } as? PlayerBattleActor ?: return false
CobblemonEvents.BATTLE_FLEE_ATTEMPT.post(BattleFleeAttemptEvent(this, runner))
runner.responses.clear()
runner.mustChoose = true
runner.request?.let { runner.sendUpdate(BattleQueueRequestPacket(it)) }
runner.sendUpdate(BattleMakeChoicePacket())
runner.entity?.sendSystemMessage(battleLang("run_prompt").white())
return true
}
/** Forces Showdown to end the battle when a [BattleActor] chooses to forfeit. */
private fun checkForfeit(): Boolean {
val forfeit = actors.find { it.responses.any { it is ForfeitActionResponse } }
@@ -1,22 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cooking.effects
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
class CleanseAllEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF) {
override fun isInstantenous() = true
override fun applyInstantenousEffect(source: Entity?, indirect: Entity?, target: LivingEntity, amplifier: Int, proximity: Double) {
target.removeAllEffects()
}
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
}
@@ -1,27 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cooking.effects
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
class CleanseNegativeEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF) {
override fun isInstantenous() = true
override fun applyInstantenousEffect(source: Entity?, indirect: Entity?, target: LivingEntity, amplifier: Int, proximity: Double) {
val snapshot = target.activeEffects.toList()
for (ei in snapshot) {
if (ei.effect.value().category == MobEffectCategory.HARMFUL) {
target.removeEffect(ei.effect)
}
}
}
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
}
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cooking.effects
import net.minecraft.server.level.ServerPlayer
import net.minecraft.stats.Stats
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectCategory
import net.minecraft.world.entity.LivingEntity
class MentalRestorationEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xAA66FF) {
override fun applyEffectTick(entity: LivingEntity, amplifier: Int): Boolean {
if (entity is ServerPlayer) {
val stats = entity.stats
val statType = Stats.CUSTOM.get(Stats.TIME_SINCE_REST)
val current = stats.getValue(statType)
val reduction = 31 * (amplifier + 1)// reduce by half a minute every second per level (30 ticks removed per tick + 1 to account for the tick passing)
val newValue = Math.max(current - reduction, 0)
stats.setValue(entity, statType, newValue)
}
return true
}
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int): Boolean {
return true
}
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.events
import com.cobblemon.mod.common.api.events.battles.BattleFaintedEvent
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
import com.cobblemon.mod.common.api.events.battles.BattleFleeAttemptEvent
import com.cobblemon.mod.common.api.events.battles.BattleStartedEvent
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
import com.cobblemon.mod.common.api.events.battles.instruction.FormeChangeEvent
@@ -111,9 +110,6 @@ object CobblemonEvents {
@JvmField
val BATTLE_STARTED_POST = EventObservable<BattleStartedEvent.Post>()
@JvmField
val BATTLE_FLEE_ATTEMPT = EventObservable<BattleFleeAttemptEvent>()
@JvmField
val BATTLE_FLED = EventObservable<BattleFledEvent>()
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.events.battles
import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
@@ -26,8 +25,7 @@ import com.cobblemon.mod.common.util.asArrayValue
data class BattleFaintedEvent(
override val battle: PokemonBattle,
val killed: BattlePokemon,
val context: BattleContext,
val pnx: String
val context: BattleContext
) : BattleEvent {
val structContext = mutableMapOf<String, MoValue>(
"battle" to battle.struct,
@@ -35,7 +33,6 @@ data class BattleFaintedEvent(
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct },
"pokemon" to killed.struct,
"context" to context.getStruct(),
"pnx" to StringValue(pnx)
"context" to context.getStruct()
)
}
}
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.battles
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.util.asArrayValue
/**
* Event fired when a [PokemonBattle] is fled by a [PlayerBattleActor].
*
* @author saultsc
* @since March 31th 2026
*/
data class BattleFleeAttemptEvent(
override val battle: PokemonBattle,
val player: PlayerBattleActor
) : BattleEvent {
val context = mutableMapOf<String, MoValue>(
"battle" to battle.struct,
"players" to battle.actors.filter { it.type == ActorType.PLAYER }.asArrayValue { it.struct },
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct }
)
}
@@ -25,8 +25,7 @@ import com.cobblemon.mod.common.util.asArrayValue
data class FormeChangeEvent(
override val battle: PokemonBattle,
val pokemon: BattlePokemon,
val formeName: String,
val pnx: String
val formeName: String
) : BattleEvent {
val context = mutableMapOf(
"battle" to battle.struct,
@@ -34,7 +33,6 @@ data class FormeChangeEvent(
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct },
"pokemon" to pokemon.struct,
"forme" to StringValue(formeName),
"pnx" to StringValue(pnx)
"forme" to StringValue(formeName)
)
}
}
@@ -9,14 +9,13 @@
package com.cobblemon.mod.common.api.interaction
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.requirement.OwnerQueryRequirement
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.data.PokemonInteractionsSyncPacket
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.requirements.PokemonPropertiesRequirement
@@ -30,11 +29,6 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.util.LowerCaseEnumTypeAdapterFactory
import net.minecraft.world.item.Item
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.levelgen.structure.Structure
import net.minecraft.world.level.material.Fluid
object PokemonInteractions : JsonDataRegistry<PokemonInteractionSet> {
override val id = cobblemonResource("pokemon_interactions")
@@ -49,42 +43,40 @@ object PokemonInteractions : JsonDataRegistry<PokemonInteractionSet> {
.registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(InteractionEffect::class.java, InteractionEffectAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Structure::class.java).type, StructureLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
.registerTypeAdapterFactory(LowerCaseEnumTypeAdapterFactory())
.setPrettyPrinting()
.create()
val interactions = mutableListOf<PokemonInteractionSet>()
val speciesInteractions = mutableListOf<PokemonInteractionSet>()
val generalInteractions = mutableListOf<PokemonInteractionSet>()
override fun sync(player: ServerPlayer) {
PokemonInteractionsSyncPacket(interactions).sendToPlayer(player)
}
override fun sync(player: ServerPlayer) {}
override fun reload(data: Map<ResourceLocation, PokemonInteractionSet>) {
interactions.clear()
val split = data.entries
.partition {
it.value.requirements.any { requirement -> requirement is PokemonPropertiesRequirement && requirement.target.species != null }
}
// Put the species specific interactions first as they take priority
interactions.addAll(split.first.map {it.value})
interactions.addAll(split.second.map {it.value})
Cobblemon.LOGGER.info("Loaded {} Pokémon interaction sets", interactions.size)
speciesInteractions.clear()
generalInteractions.clear()
val split = data.entries.partition { it.value.requirements.any { requirement -> requirement is PokemonPropertiesRequirement && requirement.target.species != null } }
speciesInteractions.addAll(split.first.map {it.value})
generalInteractions.addAll(split.second.map {it.value})
Cobblemon.LOGGER.info("Loaded {} Pokémon interaction sets", data.size)
}
fun findInteraction(pokemon: PokemonEntity): PokemonInteraction? {
val setCheck: (PokemonInteractionSet) -> Boolean = { it.requirements.all { req -> req.check(pokemon.pokemon) }}
val interactionCheck: (PokemonInteraction) -> Boolean = { it.requirements.all { req -> req.check(pokemon.pokemon) } && !pokemon.pokemon.isOnInteractionCooldown(it.grouping) }
return interactions
// species-specific interactions take priority
val validInteractions = speciesInteractions
.filter(setCheck)
.flatMap { it.interactions }
.firstOrNull(interactionCheck)
.filter(interactionCheck)
.toMutableList()
if (validInteractions.isEmpty()) { // if all species-specific interactions are absent/on cooldown, fallback to more generic ones
validInteractions.addAll(generalInteractions.filter(setCheck).flatMap { it.interactions }
.filter(interactionCheck)
)
}
return validInteractions.randomOrNull()
}
}
@@ -15,11 +15,11 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.util.*
import com.google.gson.annotations.SerializedName
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.giveOrDropItemStack
import com.cobblemon.mod.common.util.withPlayerValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.core.registries.Registries
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
@@ -28,75 +28,30 @@ import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.ItemStack
/**
* A
*/
data class PokemonInteractionSet(
val requirements: List<Requirement> = listOf(),
val interactions: List<PokemonInteraction> = listOf(),
) {
fun encode(buffer: FriendlyByteBuf) {
buffer.writeCollection(requirements) { it, requirement ->
CobblemonRequirementAdapter.encode(requirement, it)
}
buffer.writeCollection(interactions) { it, interaction ->
interaction.encode(it)
}
}
companion object {
fun decode(buffer: FriendlyByteBuf): PokemonInteractionSet {
val requirements = buffer.readList(CobblemonRequirementAdapter::decode)
val interactions = buffer.readList(PokemonInteraction::decode)
return PokemonInteractionSet(requirements, interactions)
}
}
}
val interactions: List<PokemonInteraction> = listOf()
)
data class PokemonInteraction(
val grouping: ResourceLocation,
val requirements: List<Requirement> = listOf(),
val effects: List<InteractionEffect> = listOf(),
val cooldown: ExpressionLike = "0".asExpressionLike()
) {
fun encode(buffer: FriendlyByteBuf) {
buffer.writeResourceLocation(grouping)
buffer.writeCollection(requirements) { it, requirement ->
CobblemonRequirementAdapter.encode(requirement, it)
}
buffer.writeExpressionLike(cooldown)
}
companion object {
fun decode(buffer: FriendlyByteBuf): PokemonInteraction {
val grouping = buffer.readResourceLocation()
val requirements = buffer.readList { it ->
CobblemonRequirementAdapter.decode(it)
}
// No need to sync these for now
val effects = emptyList<InteractionEffect>()
val cooldown = buffer.readExpressionLike()
return PokemonInteraction(
grouping,
requirements,
effects,
cooldown,
)
}
}
}
)
interface InteractionEffect {
fun applyEffect(pokemon: PokemonEntity, player: ServerPlayer)
}
class DropItemEffect(val item: ResourceLocation, val amount: IntRange?) : InteractionEffect {
class DropItemEffect(val item: ResourceLocation, val amount: IntRange?): InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
) {
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException(
"Cannot load item with id: $item"
)
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException("Cannot load item with id: $item")
val stack = ItemStack(item)
stack.count = amount?.randomOrNull() ?: 1
if (stack.isEmpty)
@@ -113,14 +68,12 @@ class DropItemEffect(val item: ResourceLocation, val amount: IntRange?) : Intera
}
}
class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?) : InteractionEffect {
class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?): InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
) {
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException(
"Cannot load item with id: $item"
)
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException("Cannot load item with id: $item")
val stack = ItemStack(item)
stack.count = amount?.randomOrNull() ?: 1
if (stack.isEmpty)
@@ -133,54 +86,25 @@ class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?) : Intera
}
}
class PlaySoundEffect(
val sound: ResourceLocation,
val soundSource: SoundSource?,
@SerializedName("playAround") private val _playAround: Boolean?,
@SerializedName("distance") private val _distance: Double?,
@SerializedName("volume") private val _volume: Float?,
@SerializedName("pitch") private val _pitch: Float?,
) : InteractionEffect {
class PlaySoundEffect(val sound: ResourceLocation, val soundSource: SoundSource?, val playAround: Boolean = true, val distance: Double = 64.0, val volume: Float = 1.0F, val pitch: Float = 1.0F): InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
) {
val packet = UnvalidatedPlaySoundS2CPacket(
sound,
soundSource ?: SoundSource.NEUTRAL,
pokemon.x,
pokemon.y,
pokemon.z,
volume,
pitch
)
val packet = UnvalidatedPlaySoundS2CPacket(sound, soundSource ?: SoundSource.NEUTRAL, pokemon.x, pokemon.y, pokemon.z, volume, pitch)
if (playAround) {
packet.sendToPlayersAround(pokemon.x, pokemon.y, pokemon.z, distance, pokemon.level().dimension())
packet.sendToPlayersAround( pokemon.x, pokemon.y, pokemon.z, distance, pokemon.level().dimension())
} else {
packet.sendToPlayer(player)
}
}
val playAround: Boolean
get() = _playAround != false
val distance: Double
get() = _distance ?: 64.0
val volume: Float
get() = _volume ?: 1.0F
val pitch: Float
get() = _pitch ?: 1.0F
companion object {
val ID = "play_sound"
}
}
class ShrinkItemEffect(val amount: Int = 1) : InteractionEffect {
class ShrinkItemEffect(val amount: Int = 1): InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
@@ -196,7 +120,7 @@ class ShrinkItemEffect(val amount: Int = 1) : InteractionEffect {
}
}
class ScriptEffect(val script: ExpressionLike) : InteractionEffect {
class ScriptEffect(val script: ExpressionLike): InteractionEffect {
override fun applyEffect(
pokemon: PokemonEntity,
player: ServerPlayer
@@ -145,7 +145,6 @@ import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.entity.monster.Monster
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.enchantment.EnchantmentHelper
import net.minecraft.world.level.ClipContext
import net.minecraft.world.level.GameType
import net.minecraft.world.level.Level
@@ -312,7 +311,7 @@ object MoLangFunctions {
runtime.environment.variable = params.environment.variable
val args = params.params.subList(1, params.params.size)
runtime.environment.context = ContextStruct(
(params.environment.context?.map ?: emptyMap()) + args.mapIndexed { index, value -> "arg_${index + 1}" to value }.toMap()
params.environment.context.map + args.mapIndexed { index, value -> "arg_${index + 1}" to value }.toMap()
)
val script = params.getString(0).asIdentifierDefaultingNamespace()
// store the args in the
@@ -325,24 +324,13 @@ object MoLangFunctions {
runtime.environment.context = params.environment.context
val expression = params.getString(0).asExpressionLike()
val delayInSeconds = params.getDoubleOrNull(1)?.toFloat() ?: 0.0f
fun evaluate(): MoValue {
return try {
runtime.resolve(expression)
} catch (ex: Exception) {
Cobblemon.LOGGER.warn("Failed to evaluate MoLang expression${if (delayInSeconds > 0.0f) " (delayed)" else ""}: $expression", ex)
DoubleValue.ZERO
}
}
if (delayInSeconds > 0.0f) {
val tracker = if (Cobblemon.implementation.environment() == Environment.SERVER) ServerTaskTracker else ClientTaskTracker
tracker.after(delayInSeconds) {
evaluate()
runtime.resolve(expression)
}
DoubleValue.ONE
} else {
evaluate()
runtime.resolve(expression)
}
},
"system_time_millis" to java.util.function.Function { _ ->
@@ -352,28 +340,23 @@ object MoLangFunctions {
"date_local_time" to java.util.function.Function { _ ->
val time = System.currentTimeMillis()
val date = java.util.Date(time)
val formatted = java.text.SimpleDateFormat("dd/MM/yyyy").format(date)
val formatted = java.text.SimpleDateFormat("DD/MM/YYYY").format(date)
StringValue(formatted)
},
"date_of" to java.util.function.Function { params ->
val time = params.getDouble(0).toLong()
val date = java.util.Date(time)
val formatted = java.text.SimpleDateFormat("dd/MM/yyyy").format(date)
val formatted = java.text.SimpleDateFormat("DD/MM/YYYY").format(date)
StringValue(formatted)
},
"date_is_after" to java.util.function.Function { params ->
val dateA = params.getString(0)
val dateB = params.getString(1)
val format = java.text.SimpleDateFormat("dd/MM/yyyy")
val format = java.text.SimpleDateFormat("DD/MM/YYYY")
val a = format.parse(dateA)
val b = format.parse(dateB)
DoubleValue(a.after(b))
},
"get_move_from_id" to java.util.function.Function { params ->
val moveId = params.getString(0)
val moveTemplate = Moves.getByName(moveId)
return@Function moveTemplate?.struct ?: DoubleValue.ZERO
},
"create_simple_party_provider" to java.util.function.Function { params ->
val partyProvider = SimplePartyProvider()
return@Function partyProvider.struct
@@ -384,13 +367,6 @@ object MoLangFunctions {
val pickupItem = ObtainableItem(item = item, pickupPriority = pickupPriority)
return@Function pickupItem.struct
},
"create_itemstack" to java.util.function.Function { params ->
val itemId = params.getString(0).asIdentifierDefaultingNamespace()
val item = BuiltInRegistries.ITEM.get(itemId) ?: return@Function DoubleValue.ZERO
val count = params.getIntOrNull(1) ?: 1
val itemStack = ItemStack(item, count)
return@Function ObjectValue(itemStack)
},
"file" to java.util.function.Function { MoLangLoadedFilesCache.struct }
)
val biomeFunctions = mutableListOf<(Holder<Biome>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>()
@@ -596,62 +572,6 @@ object MoLangFunctions {
}
return@put items
}
map.put("has_inventory_space") { _ ->
val inventory = player.inventory
return@put if (inventory.getFreeSlot() != -1) DoubleValue.ONE else DoubleValue.ZERO
}
map.put("set_inventory_slot") { params ->
val slot = params.getInt(0)
val inventory = player.inventory
if (slot !in 0 until inventory.containerSize) return@put DoubleValue.ZERO
val value = params.getOrNull<MoValue>(1) ?: return@put DoubleValue.ZERO
val stack: ItemStack? = when (value) {
is ObjectValue<*> -> value.obj as? ItemStack
is StringValue -> {
val id = ResourceLocation.parse(value.value)
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(id) ?: return@put DoubleValue.ZERO
ItemStack(item)
}
else -> null
}
if (stack == null) return@put DoubleValue.ZERO
inventory.setItem(slot, stack)
return@put DoubleValue.ONE
}
map.put("give_item") { params ->
val inventory = player.inventory
val freeSlot = inventory.getFreeSlot()
val value = params.getOrNull<MoValue>(0) ?: return@put DoubleValue.ZERO
val dropIfFull = params.getBooleanOrNull(1) ?: false
val stack: ItemStack? = when (value) {
is ObjectValue<*> -> value.obj as? ItemStack
is StringValue -> {
val id = ResourceLocation.parse(value.value)
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(id) ?: return@put DoubleValue.ZERO
ItemStack(item)
}
else -> null
}
if (stack == null) return@put DoubleValue.ZERO
if (freeSlot == -1) {
if (dropIfFull) {
player.drop(stack, false)
return@put DoubleValue.ONE
} else {
return@put DoubleValue.ZERO
}
}
inventory.setItem(freeSlot, stack)
return@put DoubleValue.ONE
}
map.put("face") { params -> ObjectValue(PlayerDialogueFaceProvider(player.uuid, params.getBooleanOrNull(0) != false)) }
map.put("swing_hand") { _ -> player.swing(player.usedItemHand) }
map.put("food_level") { _ -> DoubleValue(player.foodData.foodLevel) }
@@ -695,7 +615,8 @@ object MoLangFunctions {
}
map.put("active_dialogue") { _ ->
if (player.isInDialogue) {
return@put player.activeDialogue?.toMoLangStruct() ?: DoubleValue.ZERO
player.activeDialogue?.dialogueId.toString()
return@put DoubleValue.ONE
} else {
DoubleValue.ZERO
}
@@ -858,22 +779,6 @@ object MoLangFunctions {
battleStartResult.ifSuccessful { returnValue = it.struct }
return@put returnValue
}
map.put("get_custom_stat") { params ->
val statName = params.getString(0)
val resourceLocation = ResourceLocation.tryParse(statName) ?: return@put DoubleValue.ZERO
val statResourceLocation = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation) ?: return@put DoubleValue.ZERO
val exists = net.minecraft.stats.Stats.CUSTOM.contains(statResourceLocation)
if (!exists) return@put DoubleValue.ZERO
val stat = net.minecraft.stats.Stats.CUSTOM.get(statResourceLocation)
val value = player.stats.getValue(stat)
DoubleValue(value)
}
map.put("get_starter_uuid") { _ -> Cobblemon.playerDataManager.getGenericData(player).starterUUID?.let{ StringValue(it.toString()) } ?: DoubleValue.ZERO }
map.put("has_chosen_starter") { _ -> DoubleValue(Cobblemon.playerDataManager.getGenericData(player).starterSelected) }
}
map
}
@@ -894,15 +799,6 @@ object MoLangFunctions {
map.put("is_of") { params -> DoubleValue(holder.`is`(params.getString(0).asIdentifierDefaultingNamespace())) }
map.put("is_in") { params -> DoubleValue(holder.`is`(TagKey.create(Registries.ITEM, params.getString(0).replace("#", "").asIdentifierDefaultingNamespace()))) }
map.put("is_food") { params -> DoubleValue(stack.has(DataComponents.FOOD)) }
map.put("is_enchanted") { params -> DoubleValue(stack.hasFoil()) }
map.put("has_enchantment") { params ->
val enchantmentId = params.getString(0).asIdentifierDefaultingNamespace()
val minLevel = params.getIntOrNull(1) ?: 1
val enchantmentRegistry = registryAccess.registryOrThrow(Registries.ENCHANTMENT)
val holder = enchantmentRegistry.getHolder(enchantmentId).orElse(null) ?: return@put DoubleValue.ZERO
val level = EnchantmentHelper.getItemEnchantmentLevel(holder, stack)
return@put DoubleValue(level >= minLevel)
}
return@mutableListOf map
}
)
@@ -1842,60 +1738,23 @@ object MoLangFunctions {
map.put("remove_cosmetic_item") { _ ->
pokemon.removeCosmeticItem()
}
map.put("marks") { _ -> pokemon.marks.asArrayValue { StringValue(it.identifier.toString()) } }
map.put("has_mark") { params ->
var hasMark = false
val identifier = params.getString(0).asIdentifierDefaultingNamespace()
val mark = Marks.getByIdentifier(identifier)
if (mark != null) {
hasMark = pokemon.marks.contains(mark)
}
DoubleValue(hasMark)
}
map.put("remove_marks") { params ->
var removedMark = false
for (param in params.params) {
val identifier = param.asString().asIdentifierDefaultingNamespace()
val mark = Marks.getByIdentifier(identifier)
if (mark != null) {
pokemon.exchangeMark(mark, false)
removedMark = true
}
}
DoubleValue(removedMark)
}
map.put("add_marks") { params ->
var appliedMark = false
for (param in params.params) {
val identifier = param.asString().asIdentifierDefaultingNamespace()
val mark = Marks.getByIdentifier(identifier)
if (mark != null) {
pokemon.exchangeMark(mark, true)
appliedMark = true
}
if (mark != null) pokemon.exchangeMark(mark, true)
}
DoubleValue(appliedMark)
}
map.put("add_marks_with_chance") { params ->
var appliedMark = false
for (param in params.params) {
val identifier = param.asString().asIdentifierDefaultingNamespace()
val mark = Marks.getByIdentifier(identifier)
mark?.let {
val probability = it.chance.coerceIn(0F, 1F) * 100
val randomValue = Random.nextDouble(0.0, 100.0)
if (randomValue < probability) {
pokemon.exchangeMark(it, true)
appliedMark = true
}
if (randomValue < probability) pokemon.exchangeMark(it, true)
}
}
DoubleValue(appliedMark)
}
map.put("add_potential_marks") { params ->
for (param in params.params) {
@@ -2059,13 +1918,9 @@ object MoLangFunctions {
}
}
map.put("is_sprinting") {
if (pokemonEntity.hasControllingPassenger()) { // If its being ridden then the riding state sets the animation
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
return@ifRidingAvailableSupply moValue.functions.get("sprinting")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
}
} else {
pokemonEntity.isPokemonSprinting
pokemonEntity.ifRidingAvailableSupply(DoubleValue.ZERO) { behaviour, settings, state ->
val moValue = behaviour.asMoLangValue(settings, state, pokemonEntity)
return@ifRidingAvailableSupply moValue.functions.get("sprinting")?.apply(MoParams.EMPTY) as? MoValue ?: DoubleValue.ZERO
}
}
map.put("is_drifting") {
@@ -2855,8 +2710,8 @@ object MoLangFunctions {
}
variable
}
else -> VariableStruct()
}
else -> null
} ?: throw IllegalArgumentException("Invalid NBT element type: ${nbt.type}")
}
}
@@ -58,15 +58,12 @@ open class MoveTemplate(
val struct: MoStruct by lazy {
QueryStruct(hashMapOf())
.addFunction("name") { StringValue(name) }
.addFunction("display_name") { StringValue(displayName.string) }
.addFunction("description") { StringValue(description.string) }
.addFunction("type") { StringValue(elementalType.showdownId) }
.addFunction("damage_category") { StringValue(damageCategory.name) }
.addFunction("power") { DoubleValue(power) }
.addFunction("target") { StringValue(target.name) }
.addFunction("accuracy") { DoubleValue(accuracy) }
.addFunction("pp") { DoubleValue(pp) }
.addFunction("max_pp") { DoubleValue(maxPp) }
.addFunction("priority") { DoubleValue(priority) }
.addFunction("crit_ratio") { DoubleValue(critRatio) }
}
@@ -289,11 +289,11 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
createDefault("ancient_great_ball", MultiplierModifier(1.5F), ancient = true)
createDefault("ancient_ultra_ball", MultiplierModifier(2F), ancient = true)
createDefault("ancient_heavy_ball", throwPower = 0.75f, ancient = true)
createDefault("ancient_leaden_ball", MultiplierModifier(1.5F), throwPower = 0.75f, ancient = true)
createDefault("ancient_gigaton_ball", MultiplierModifier(2F), throwPower = 0.75f, ancient = true)
createDefault("ancient_leaden_ball", throwPower = 0.75f, ancient = true)
createDefault("ancient_gigaton_ball", throwPower = 0.75f, ancient = true)
createDefault("ancient_feather_ball", throwPower = 2.5f, ancient = true)
createDefault("ancient_wing_ball", MultiplierModifier(1.5F), throwPower = 2.5f, ancient = true)
createDefault("ancient_jet_ball", MultiplierModifier(2F), throwPower = 2.5f, ancient = true)
createDefault("ancient_wing_ball", throwPower = 2.5f, ancient = true)
createDefault("ancient_jet_ball", throwPower = 2.5f, ancient = true)
createDefault("ancient_origin_ball", GuaranteedModifier(), ancient = true)
// Luxury ball effect, low priority as it must be triggered before soothe bell as of gen 4
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOW) { event ->
@@ -314,11 +314,11 @@ object PokemonSpecies : JsonDataRegistry<Species> {
val result = mutableMapOf<String, String>()
this.species.forEach {species ->
val baseSpecies = ShowdownSpecies(species, null)
result[ShowdownIdentifiable.REGEX.replace(baseSpecies.name.lowercase(), "")] = this.gson.toJson(baseSpecies)
result[ShowdownIdentifiable.REGEX.replace(baseSpecies.name, "")] = this.gson.toJson(baseSpecies)
species.forms.forEach { form ->
if (form != species.standardForm) {
val formSpecies = ShowdownSpecies(species, form)
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name.lowercase(), "")] = this.gson.toJson(formSpecies)
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name, "")] = this.gson.toJson(formSpecies)
}
}
}
@@ -80,9 +80,7 @@ open class ChoiceSpeciesFeatureProvider(
internal constructor(): this(emptyList())
override fun get(pokemon: Pokemon): StringSpeciesFeature? {
return pokemon.features.filterIsInstance<StringSpeciesFeature>().find { it.name in keys }
}
override fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
override fun invoke(pokemon: Pokemon): StringSpeciesFeature? {
val existing = get(pokemon)
@@ -103,15 +101,15 @@ open class ChoiceSpeciesFeatureProvider(
}
override fun invoke(nbt: CompoundTag): StringSpeciesFeature? {
val key = keys.find { nbt.contains(it) }
if (key == null) return null
return StringSpeciesFeature(key, "").also { it.loadFromNBT(nbt) }
return if (nbt.contains(keys.first())) {
StringSpeciesFeature(keys.first(), "").also { it.loadFromNBT(nbt) }
} else null
}
override fun invoke(json: JsonObject): StringSpeciesFeature? {
val key = keys.find { json.has(it) }
if (key == null) return null
return StringSpeciesFeature(key, "").also { it.loadFromJSON(json) }
return if (json.has(keys.first())) {
StringSpeciesFeature(keys.first(), "").also { it.loadFromJSON(json) }
} else null
}
override fun fromString(value: String?): StringSpeciesFeature? {
@@ -133,7 +131,7 @@ open class ChoiceSpeciesFeatureProvider(
override fun provide(properties: PokemonProperties): Set<String> {
return if (isAspect) {
val feature = properties.customProperties.filterIsInstance<StringSpeciesFeature>().find { it.name in keys }
val feature = properties.customProperties.filterIsInstance<StringSpeciesFeature>().find { it.name == keys.first() }
if (feature != null) {
setOf(getAspect(feature))
} else {
@@ -132,9 +132,7 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
constructor(vararg keys: String) : this(keys.toList())
override fun get(pokemon: Pokemon): FlagSpeciesFeature? {
return pokemon.features.filterIsInstance<FlagSpeciesFeature>().find { it.name in keys }
}
override fun get(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(keys.first())
override fun invoke(pokemon: Pokemon): FlagSpeciesFeature? {
return get(pokemon)
@@ -146,15 +144,15 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
}
override fun invoke(nbt: CompoundTag): FlagSpeciesFeature? {
val key = keys.find { nbt.contains(it) }
if (key == null) return null
return FlagSpeciesFeature(key, false).also { it.loadFromNBT(nbt) }
return if (nbt.contains(keys.first())) {
FlagSpeciesFeature(keys.first(), false).also { it.loadFromNBT(nbt) }
} else null
}
override fun invoke(json: JsonObject): FlagSpeciesFeature? {
val key = keys.find { json.has(it) }
if (key == null) return null
return FlagSpeciesFeature(key, false).also { it.loadFromJSON(json) }
return if (json.has(keys.first())) {
FlagSpeciesFeature(keys.first(), false).also { it.loadFromJSON(json) }
} else null
}
override fun fromString(value: String?): FlagSpeciesFeature? {
@@ -172,26 +170,16 @@ class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpecie
}
override fun provide(pokemon: Pokemon): Set<String> {
return if (isAspect) {
val feature = pokemon.features.filterIsInstance<FlagSpeciesFeature>().find { it.name in keys }
if (feature != null && feature.enabled) {
setOf(keys.first())
} else {
emptySet()
}
return if (isAspect && pokemon.getFeature<FlagSpeciesFeature>(keys.first())?.enabled == true) {
setOf(keys.first())
} else {
emptySet()
}
}
override fun provide(properties: PokemonProperties): Set<String> {
return if (isAspect) {
val feature = properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name in keys }
if (feature != null && feature.enabled) {
setOf(keys.first())
} else {
emptySet()
}
return if (isAspect && properties.customProperties.filterIsInstance<FlagSpeciesFeature>().find { it.name == keys.first() }?.enabled == true) {
setOf(keys.first())
} else {
emptySet()
}
@@ -142,15 +142,19 @@ class IntSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<IntSpeciesF
}
override fun invoke(nbt: CompoundTag): IntSpeciesFeature? {
val key = keys.find { nbt.contains(it) }
if (key == null) return null
return IntSpeciesFeature(keys.first(), nbt.getInt(key));
return if (nbt.contains(keys.first())) {
IntSpeciesFeature(keys.first(), nbt.getInt(keys.first()))
} else {
null
}
}
override fun invoke(json: JsonObject): IntSpeciesFeature? {
val key = keys.find { json.has(it) }
if (key == null) return null
return IntSpeciesFeature(keys.first(), json.get(key).asInt)
return if (json.has(keys.first())) {
IntSpeciesFeature(keys.first(), json.get(keys.first()).asInt)
} else {
null
}
}
override fun get(pokemon: Pokemon) = pokemon.features.filterIsInstance<IntSpeciesFeature>().find { it.name in keys }
@@ -102,12 +102,6 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
@JvmStatic
fun register(name: String, provider: SpeciesFeatureProvider<*>) = register(name, provider, isCoded = true)
@JvmStatic
fun registerType(key: String, clazz: Class<out SpeciesFeatureProvider<*>>) {
types[key] = clazz
}
private fun registerFromAssets(identifier: ResourceLocation, provider: SpeciesFeatureProvider<*>) = register(identifier.path, provider, isCoded = false)
@JvmStatic
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
/**
* A [Requirement] that expects a [LivingEntity] to be attached to the [Pokemon].
@@ -27,7 +26,7 @@ interface OwnerQueryRequirement : Requirement {
override fun check(pokemon: Pokemon): Boolean {
val owner = pokemon.getOwnerEntity() ?: return false
return when (owner) {
is Player -> {
is ServerPlayer -> {
this.checkPlayer(pokemon, owner)
}
is NPCEntity -> {
@@ -38,13 +37,13 @@ interface OwnerQueryRequirement : Requirement {
}
/**
* Checks if the given [Pokemon] & [Player] satisfies the requirement.
* Checks if the given [Pokemon] & [ServerPlayer] satisfies the requirement.
*
* @param pokemon The [Pokemon] being queried.
* @param owner The [Player] that owns this [Pokemon].
* @param owner The [ServerPlayer] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
fun checkPlayer(pokemon: Pokemon, owner: ServerPlayer): Boolean
/**
* Checks if the given [Pokemon] & [NPCEntity] satisfies the requirement.
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.reactive
import com.cobblemon.mod.common.api.events.Cancelable
open class EventObservable<T> : SimpleObservable<T>() {
@JvmOverloads
inline fun post(vararg events: T, then: (T) -> Unit = {}) {
// Issuing generic-typed pass-throughs to varargs doesn't work
// properly unless the source is a vararg as well, complicated story.
@@ -119,10 +119,7 @@ class RidingController(
private fun canTransitionToLand(): Boolean {
if ((entity.isUnderWater)) return false
if ((entity.isEyeInFluid(FluidTags.WATER) || entity.isEyeInFluid(FluidTags.LAVA))) return false
// If the currently in the air but has no land style then don't transition and render the ride useless.
// Hover is a good example for this.
val shouldStayInAir = entity.pokemon.riding.behaviours?.get(RidingStyle.LAND) == null && context?.style == RidingStyle.AIR
return entity.onGround() && !shouldStayInAir
return entity.onGround()
}
private fun canTransitionToLiquid(): Boolean {
@@ -213,23 +213,10 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalHover.accelerationExpr!!) * 20.0)
var newVelocity = state.rideVelocity.get()
val unrotateVel = vehicle.deltaMovement.yRot(vehicle.yRot)
val vehicleFrontVec = Vec3(0.0, 0.0, 1.0)
val faceVel = Vec3(vehicle.deltaMovement.x, 0.0, vehicle.deltaMovement.z)
val d = vehicle.deltaMovement.horizontalDistance()
val v2 = Vec3(faceVel.dot(Vec3(1.0, 0.0, 0.0)) * d, newVelocity.y, faceVel.dot(Vec3(0.0, 0.0, 1.0)) * d)
// Check for collisions and if found, update the speed to reflect it
if (vehicle.horizontalCollision) {
val smackingIntoWallSpeed = max( vehicle.deltaMovement.horizontalDistance(), 0.2)
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z).normalize().scale(smackingIntoWallSpeed).add(0.0, newVelocity.y, 0.0)
}
if (vehicle.verticalCollision) {
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z)
if (vehicle.verticalCollision || vehicle.horizontalCollision) {
state.speed.set(vehicle.deltaMovement.length())
}
// align the velocity vector to be in local vehicle space
@@ -322,7 +322,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
val pitchRot = handling * state.currMouseYForce.get()
// Roll
val rollRot = handling * state.currMouseXForce.get()
val rollRot = handling * 1.5 * state.currMouseXForce.get()
val mouseRotation = Vec3(0.0, pitchRot, rollRot)
@@ -41,6 +41,10 @@ interface CompositeRidingStrategy<T : CompositeSettings> {
toState: RidingBehaviourState,
toSettings: RidingBehaviourSettings
) {
if (vehicle.level().isClientSide) {
val fromSettings = if (settings.defaultBehaviour == toSettings) settings.alternateBehaviour else settings.defaultBehaviour
}
toState.stamina.set(fromState.stamina.get())
toState.rideVelocity.set(fromState.rideVelocity.get())
fromState.reset()
@@ -34,6 +34,7 @@ import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.writeNullableExpression
import com.cobblemon.mod.common.util.writeRidingStats
import net.minecraft.client.Minecraft
import net.minecraft.client.player.LocalPlayer
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
@@ -114,10 +115,10 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
input: Vec3
) {
if (vehicle.level().isClientSide) {
handleSprinting(state, driver)
handleSprinting(state)
inAirCheck(state, vehicle)
tickStamina(settings, state, vehicle)
state.walking.set(state.rideVelocity.get().horizontalDistance() > 0.01 || driver.zza != 0.0f)
state.walking.set(state.rideVelocity.get().horizontalDistance() > 0.01)
}
}
@@ -139,24 +140,9 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
}
fun handleSprinting(
state: HorseState,
driver: Player
state: HorseState
) {
val sprintTimerTickLength = 7 // Emulate vanillas tick timer length
var hasDoubleTapped = false
// If you are not sprinting and you just pressed down and theres no
if (!state.forwardHeldLastTick.get() && Minecraft.getInstance().options.keyUp.isDown() && !state.sprinting.get() && state.sprintTickTimer.get() == 0) {
state.sprintTickTimer.set(sprintTimerTickLength)
} else if (!state.forwardHeldLastTick.get() && Minecraft.getInstance().options.keyUp.isDown() && state.sprintTickTimer.get() != 0) { // If has double tapped
hasDoubleTapped = true
}else if(!state.sprinting.get() && state.sprintTickTimer.get() > 0) {
state.sprintTickTimer.set(state.sprintTickTimer.get() - 1)
} else {
state.sprintTickTimer.set(0)
}
val tryingToSprint = (Minecraft.getInstance().options.keySprint.isDown() && Minecraft.getInstance().options.keyUp.isDown()) || hasDoubleTapped
val tryingToSprint = Minecraft.getInstance().options.keySprint.isDown() && Minecraft.getInstance().options.keyUp.isDown()
if (state.stamina.get() <= 0.0f || !Minecraft.getInstance().options.keyUp.isDown()) {
// If stamina runs out or the player is not holding forward then stop sprinting
@@ -171,9 +157,6 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
// If you are trying to sprint and the toggle allows it then start sprinting and disable toggle
state.sprinting.set(true)
}
// Take not of whether forward was held last tick
state.forwardHeldLastTick.set(Minecraft.getInstance().options.keyUp.isDown())
}
fun tickStamina(
@@ -187,16 +170,17 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
return
}
var newStam = stam
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalHorse.staminaExpr!!)).toFloat() / 20.0f
val newStam = if (state.sprinting.get()) {
max(0.0f,stam - stamDrainRate)
if (state.sprinting.get()) {
newStam = max(0.0f,stam - stamDrainRate)
} else {
min(1.0f,stam + stamDrainRate * 4)
newStam = min(1.0f,stam + stamDrainRate * 4)
}
state.stamina.set(newStam.coerceIn(0F, 1F))
state.stamina.set(newStam)
}
override fun updatePassengerRotation(
@@ -244,7 +228,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
// Normalize the current rotation diff
val rotDiff = Mth.wrapDegrees(driver.yRot - vehicle.yRot).coerceIn(-maxYawDiff,maxYawDiff)
val rotDiffNorm = rotDiff / maxYawDiff//(rotDiff / maxYawDiff).coerceIn(-0.2f, 0.2f)
val rotDiffNorm = rotDiff / maxYawDiff
// Take the square root so that the ride levels out quicker when at lower differences between entity
// y and driver y
@@ -257,7 +241,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
val walkSpeed = getWalkSpeed(vehicle)
val w = max(walkSpeed, vehicle.deltaMovement.horizontalDistance())
val invRelSpeed = (RidingBehaviour.scaleToRange(w, walkSpeed, topSpeed ) - 1.0f) * -1.0f
val turnRate = ((handling.toFloat() / 20.0f) * max(walkHandlingBoost * sqrt(abs(invRelSpeed)), 1.0)).toFloat()
val turnRate = ((handling.toFloat() / 20.0f) * max(walkHandlingBoost * invRelSpeed, 1.0)).toFloat()
// Ensure you only ever rotate as much difference as there is between the angles.
val turnSpeed = turnRate * rotDiffMod
@@ -290,24 +274,30 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalHorse.speedExpr!!)
val walkSpeed = getWalkSpeed(vehicle)
val topSpeed = if(canSprint && state.sprinting.get()) rideTopSpeed else walkSpeed
val accelTime = if(state.sprinting.get()) (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalHorse.accelerationExpr!!) * 20.0) else 0.5 * 20.0
val accel = topSpeed / accelTime
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalHorse.accelerationExpr!!) * 20.0)
var activeInput = false
/******************************************************
* Gather the previous velocity and check for horizontal
* collisions
*****************************************************/
val dmSpeed = vehicle.deltaMovement.length()
val rvSpeed = state.rideVelocity.get().length()
var newVelocity = state.rideVelocity.get() //.normalize().scale(vehicle.deltaMovement.horizontalDistance())
/******************************************************
* Gather the previous velocity and check for horizontal
* collisions
*****************************************************/
// if (dmSpeed > rvSpeed) {
// // align the velocity vector to be in local vehicle space
// newVelocity = vehicle.deltaMovement
// val yawAligned = Matrix3f().rotateY(-vehicle.yRot.toRadians())
// newVelocity = (newVelocity.toVector3f().mul(yawAligned)).toVec3d()
// }
if (vehicle.horizontalCollision) {
var horizontalVec = Vec3(newVelocity.x, 0.0, newVelocity.z)
horizontalVec = horizontalVec.normalize().scale(min(horizontalVec.length(), 0.3))
newVelocity = Vec3(horizontalVec.x, newVelocity.y, horizontalVec.z)
newVelocity = newVelocity.normalize().scale(vehicle.deltaMovement.length())
}
/******************************************************
@@ -383,7 +373,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
state.jumpTicks.set(state.jumpTicks.get() + 1)
}
// Zero out lateral velocity possibly picked up from a controller transition
//Zero out lateral velocity possibly picked up from a controller transition
newVelocity = Vec3(0.0, newVelocity.y, newVelocity.z)
@@ -472,7 +462,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
vehicle: PokemonEntity,
driver: Player
): Float {
return if (state.sprinting.get()) 1.15f else 1.0f
return 1.0f
}
override fun useAngVelSmoothing(
@@ -531,14 +521,6 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
return true
}
override fun maxUpStep(
settings: HorseSettings,
state: HorseState,
vehicle: PokemonEntity
): Float? {
return if (state.inAir.get()) 0.0f else 1.2f
}
override fun getRideSounds(
settings: HorseSettings,
state: HorseState,
@@ -637,8 +619,6 @@ class HorseState : RidingBehaviourState() {
var sprintToggleable = ridingState(false, Side.CLIENT)
var inAir = ridingState(false, Side.CLIENT)
var jumpTicks = ridingState(0, Side.CLIENT)
var sprintTickTimer = ridingState(0, Side.CLIENT)
var forwardHeldLastTick = ridingState(false, Side.CLIENT)
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
@@ -647,8 +627,6 @@ class HorseState : RidingBehaviourState() {
buffer.writeBoolean(sprintToggleable.get())
buffer.writeBoolean(inAir.get())
buffer.writeInt(jumpTicks.get())
buffer.writeInt(sprintTickTimer.get())
buffer.writeBoolean(forwardHeldLastTick.get())
}
override fun decode(buffer: FriendlyByteBuf) {
@@ -658,8 +636,6 @@ class HorseState : RidingBehaviourState() {
sprintToggleable.set(buffer.readBoolean(), forced = true)
inAir.set(buffer.readBoolean(), forced = true)
jumpTicks.set(buffer.readInt(), forced = true)
sprintTickTimer.set(buffer.readInt(), forced = true)
forwardHeldLastTick.set(buffer.readBoolean(), forced = true)
}
override fun reset() {
@@ -669,8 +645,6 @@ class HorseState : RidingBehaviourState() {
sprintToggleable.set(false, forced = true)
inAir.set(false, forced = true)
jumpTicks.set(0, forced = true)
sprintTickTimer.set(0, forced = true)
forwardHeldLastTick.set(false, forced = true)
}
override fun copy() = HorseState().also {
@@ -681,8 +655,6 @@ class HorseState : RidingBehaviourState() {
it.sprintToggleable.set(this.sprintToggleable.get(), forced = true)
it.inAir.set(this.inAir.get(), forced = true)
it.jumpTicks.set(this.jumpTicks.get(), forced = true)
it.sprintTickTimer.set(this.sprintTickTimer.get(), forced = true)
it.forwardHeldLastTick.set(this.forwardHeldLastTick.get(), forced = true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
@@ -100,7 +100,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
driver: Player,
input: Vec3
) {
if (vehicle.level().isClientSide) {
if(vehicle.level().isClientSide) {
handleBoosting(state, vehicle)
tickStamina(settings, state, vehicle)
}
@@ -147,7 +147,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
val stamDrainRate = (1.0f / boostTime).toFloat()
val newStam = if (state.boosting.get()) max(0.0f,stam - stamDrainRate)
else (stam + stamDrainRate).coerceIn(0F, 1F)
else min(1.0f,stam + stamDrainRate)
state.stamina.set(newStam)
}
@@ -60,7 +60,7 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
val poseProvider = PoseProvider<SubmarineSettings, SubmarineState>(PoseType.FLOAT)
.with(PoseOption(PoseType.SWIM) { _, state, entity -> state.rideVelocity.get().z > 0.05 && !state.onSurface.get()})
.with(PoseOption(PoseType.STAND) { _, state, entity -> state.rideVelocity.get().z <= 0.05 && state.onSurface.get()})
.with(PoseOption(PoseType.SWIM) { _, state, entity -> state.rideVelocity.get().z > 0.05 && state.onSurface.get()})
.with(PoseOption(PoseType.STAND) { _, state, entity -> state.rideVelocity.get().z > 0.05 && state.onSurface.get()})
override fun isActive(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
return vehicle.isInWater || !vehicle.onGround()
@@ -191,17 +191,11 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
* Calculate Forward Velocity
*********************************************/
val currZVel = state.rideVelocity.get().z
var newZVel = when {
val newZVel = when {
driver.zza > 0.0 -> min(topSpeed, currZVel + accel)
driver.zza < 0.0 -> max( -strafeSpeed, currZVel - strafeAccel)
else -> lerp(currZVel, 0.0, 0.02)
driver.zza < 0.0 -> max( -strafeSpeed, currZVel - strafeAccel) //TODO: Might need to be applied in addition to the normal braking force?
else -> lerp(currZVel, 0.0, 0.05)
}
// If trying to brake then add the friction to the braking force
if (driver.zza != 0.0f && driver.zza.sign.toDouble() != newZVel.sign) {
newZVel = lerp(newZVel, 0.0, 0.02)
}
currVel = Vec3(currVel.x, currVel.y, newZVel)
/*********************************************
@@ -212,20 +206,14 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.4
val terminalYVel = 2.0
val driverYInput = if(driver.jumping) 1.0 else if (driver.isShiftKeyDown) -1.0 else 0.0
var newYVel = when {
val newYVel = when {
(!vehicle.isInWater) -> max(-terminalYVel, currYVel - gravity)
//(vehicle.isInWater && !vehicle.isUnderWater && currYVel > 0.001) -> lerp(currYVel, 0.0, 0.1) // Make sure that yVel is above a threshold before doing this otherwise it'll block submerging.
//driverYInput != 0.0 && currYVel > 0.001 && driverYInput.sign != currYVel.sign -> lerp(currYVel, 0.0, 0.05)
driverYInput > 0.0 -> min(vertTopSpeed, currYVel + strafeAccel)
driverYInput < 0.0 -> max(-vertTopSpeed, currYVel - strafeAccel)
else -> lerp(currYVel, 0.0, 0.02)
else -> lerp(currYVel, 0.0, 0.05)
}
// If trying to brake then add the friction to the braking force
if (driverYInput != 0.0 && driverYInput != newYVel.sign) {
newYVel = lerp(newYVel, 0.0, 0.02)
}
currVel = Vec3(currVel.x, newYVel, currVel.z)
/*********************************************
@@ -233,17 +221,11 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
*********************************************/
val currXVel = state.rideVelocity.get().x
val horzTopSpeed = strafeSpeed
var newXVel = when {
val newXVel = when {
driver.xxa > 0.0 -> min(horzTopSpeed, currXVel + strafeAccel)
driver.xxa < 0.0 -> max( -horzTopSpeed, currXVel - strafeAccel)
else -> lerp(currXVel, 0.0, 0.02)
else -> lerp(currXVel, 0.0, 0.01)
}
// If trying to brake then add the friction to the braking force
if (driver.xxa != 0.0f && driver.xxa.sign.toDouble() != newZVel.sign) {
newXVel = lerp(newXVel, 0.0, 0.02)
}
currVel = Vec3(newXVel, currVel.y, currVel.z)
// Set the new velocity
@@ -323,6 +305,81 @@ class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
}
private fun correctOrientation(
settings: SubmarineSettings,
state: SubmarineState,
vehicle: PokemonEntity,
controller: OrientationController,
driver: Player,
deltaTime: Double
) {
// TODO: remove if not needed
// // Calculate correcting roll force.
// // If the ride is moving then have the correction rate be an equal proportion of:
// // - how rolled are you
// // - how long has it been since last mouse input (higher is stronger correction)
// // Also the correction is proportional as a whole to how NOT pitched are you so you don't spin endlessly when looking up or down
// val howRolledAmI = sqrt(abs((cos(controller.roll.toRadians()) - 1.0f) * 0.5f)) // sqrt so it trends towards one pretty quickly
// val maxRollCorrectionRate =
// if (state.rideVelocity.get().length() < 0.2) 10.0f * abs(cos(controller.pitch.toRadians()))
// else 10.0f * cos(controller.pitch.toRadians()).pow(2) * (
// howRolledAmI*1.0f +
// (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
// )
// val maxRollForce = maxRollCorrectionRate / 40.0f
// val rollArrivalDeg = 60.0f
// val desiredRoll = 0.0f
//
// // Calculate the signed error (how far and in what direction)
// val rollError = Mth.wrapDegrees(desiredRoll.angleDifference(controller.roll))
//
// // Use the absolute error to calculate the magnitude of the influence
// val influenceMagnitude = (min(rollArrivalDeg, abs(rollError)) / rollArrivalDeg)
// val desiredRollForce = maxRollCorrectionRate * influenceMagnitude * -rollError.sign
// var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
//
// // Ensure the 'steering' correction force doesn't exceed our maxForce
// if (abs(steeredRollForce) > maxRollForce) {
// steeredRollForce = steeredRollForce.sign * maxRollForce
// }
//
// // Apply the 'steered' force (its really not a steering force I need a better name)
// state.currRollCorrectionForce.set(
// state.currRollCorrectionForce.get() + steeredRollForce
// )
//Calculate correcting pitch force.
// val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalSubmarine.timeToRollCorrect!!)
// val maxPitchCorrectionRate = 5.0f * (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
// val maxPitchForce = maxPitchCorrectionRate / 40.0f
// val pitchArrivalDeg = 45.0f
// val desiredPitch = 0.0f
//
// if(state.rideVelocity.get().length() < 0.1 && state.noInputTime.get() > rollCorrectionTimer) {
// val pitchErrror = Mth.wrapDegrees(desiredPitch.angleDifference(controller.pitch))
// val arrivalInfluence = (min(pitchArrivalDeg,abs(pitchErrror)) / pitchArrivalDeg)
// val desiredPitchForce = maxPitchCorrectionRate * arrivalInfluence * -pitchErrror.sign
// var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
//
// // Ensure the 'steering' correction force doesn't exceed our maxForce
// if (abs(steeredPitchForce) > maxPitchForce) {
// steeredPitchForce = steeredPitchForce.sign * maxPitchForce
// }
//
// // Apply the 'steered' force (its really not a steering force I need a better name)
// state.currPitchCorrectionForce.set(
// state.currPitchCorrectionForce.get() + steeredPitchForce
// )
// } else {
// state.currPitchCorrectionForce.set(
// //reduce rollCorrection gradually
// lerp(state.currPitchCorrectionForce.get(), 0.0, deltaTime * 0.98)
// )
// }
}
override fun rotationOnMouseXY(
settings: SubmarineSettings,
state: SubmarineState,
@@ -12,7 +12,6 @@ package com.cobblemon.mod.common.api.riding.sound
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeState
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.getIsSubmerged
import com.cobblemon.mod.common.util.resolveDouble
import net.minecraft.client.Minecraft
import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance
@@ -66,21 +65,6 @@ class RideLoopSound(val ride: PokemonEntity, val soundSettings: RideSoundSetting
return
}
// Mute the sound if it's not meant to play for the passenger
if (this.isPassenger && !this.soundSettings.playForPassengers) {
this.volume = 0.0f
return
}
// Mute sounds when submerged unless they support underwater sounds, underwater sounds don't play above water
if (this.ride.getIsSubmerged() && !this.soundSettings.submerged) {
this.volume = 0.0f
return
} else if (!this.ride.getIsSubmerged() && this.soundSettings.submerged) {
this.volume = 0.0f
return
}
// Perform data driven pitch and volume calculation
this.volume = ((soundSettings.volumeExpr.let { ride.runtime.resolveDouble(it) })).toFloat()
this.volume *= this.fade
@@ -27,9 +27,7 @@ data class RideSoundSettings(
val soundLocation: ResourceLocation,
@SerializedName("volumeExpr") private val _volumeExpr: Expression? = "1.0".asExpression(),
@SerializedName("pitchExpr") private val _pitchExpr: Expression? = "1.0".asExpression(),
val playForPassengers: Boolean = true,
val playForNonPassengers: Boolean = false,
val submerged: Boolean = false,
val muffleEnabled: Boolean = false,
@SerializedName("attenuationModel") private val _attenuationModel: RideAttenuationModel? = RideAttenuationModel.NONE
): Encodable {
@@ -48,9 +46,7 @@ data class RideSoundSettings(
buffer.writeResourceLocation(soundLocation)
buffer.writeExpression(volumeExpr)
buffer.writeExpression(pitchExpr)
buffer.writeBoolean(playForPassengers)
buffer.writeBoolean(playForNonPassengers)
buffer.writeBoolean(submerged)
buffer.writeBoolean(muffleEnabled)
buffer.writeEnum(attenuationModel)
}
@@ -61,9 +57,7 @@ data class RideSoundSettings(
val soundLocation = buffer.readResourceLocation()
val volumeExpr = buffer.readExpression()
val pitchExpr = buffer.readExpression()
val playForPassengers = buffer.readBoolean()
val playForNonPassengers = buffer.readBoolean()
val submerged = buffer.readBoolean()
val muffleEnabled = buffer.readBoolean()
val attenuationModel = buffer.readEnum(RideAttenuationModel::class.java)
@@ -71,9 +65,7 @@ data class RideSoundSettings(
soundLocation,
volumeExpr,
pitchExpr,
playForPassengers,
playForNonPassengers,
submerged,
muffleEnabled,
attenuationModel
)
@@ -54,6 +54,8 @@ class RidingAnimationData(val ride: PokemonEntity)
fun update() {
val activeRide = ride.hasControllingPassenger()
if (!activeRide) return
var currRot = Vec3.ZERO
var angDelta = Vec3.ZERO
@@ -151,16 +153,14 @@ class RidingAnimationData(val ride: PokemonEntity)
/******************************************************
* Update springs
*****************************************************/
if (activeRide) {
val driver = ride.controllingPassenger
val vertInput = when {
driver != null && driver.jumping-> 1.0
driver != null && driver.isShiftKeyDown -> -1.0
else -> 0.0
}
val input = if(driver != null) Vec3(driver.xxa.toDouble() * -1, vertInput, driver.zza.toDouble()) else Vec3.ZERO
driverInputSpring.update(input, stiffness * 2, damping)
val driver = ride.controllingPassenger
val vertInput = when {
driver != null && driver.jumping-> 1.0
driver != null && driver.isShiftKeyDown -> -1.0
else -> 0.0
}
val input = if(driver != null) Vec3(driver.xxa.toDouble() * -1, vertInput, driver.zza.toDouble()) else Vec3.ZERO
driverInputSpring.update(input, stiffness * 2, damping)
rotDeltaSpring.update(angDelta, stiffness, damping)
velocitySpring.update(currentVelocity, stiffness, damping)
rotSpring.update(currRot, stiffness, damping)
@@ -44,7 +44,6 @@ import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
import com.cobblemon.mod.common.api.spawning.preset.PokemonSpawnDetailPreset
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
import com.cobblemon.mod.common.api.spawning.spawner.BasicSpawner
import com.cobblemon.mod.common.api.spawning.spawner.FishingSpawnerFactory
import com.cobblemon.mod.common.api.spawning.spawner.FixedAreaSpawner
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
@@ -140,6 +139,19 @@ object BestSpawner {
fun onServerStarted(server: MinecraftServer) {
CobblemonSpawnPools.onServerLoad(server)
fishingSpawner = FishingSpawnerFactory.createSharedSpawner()
fishingSpawner = BasicSpawner(
name = "fishing",
spawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
).also {
it.influences.add(
BucketMultiplyingInfluence(
multipliers = mapOf(
"uncommon" to 2.25f,
"rare" to 5.5f,
"ultra-rare" to 5.5f,
)
)
)
}
}
}
@@ -44,7 +44,11 @@ abstract class SpawnAction<R>(
spawnablePosition.applyInfluences { it.affectAction(this) }
val result = run()
future.complete(result)
if (result != null) {
future.complete(result)
} else {
future.completeExceptionally(Exception("Nothing was spawned."))
}
return result
}
@@ -26,7 +26,7 @@ import net.minecraft.world.entity.Entity
/**
* A [SpawningInfluence] that applies some number of SpawnBait effects.
*
* @author Hiroku, Plastered_Crab, ppVon
* @author Hiroku, Plastered_Crab
* @since March 18th, 2025
*/
open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (time: Int, entity: PokemonEntity?) -> Unit = { _, _ -> }) : SpawningInfluence {
@@ -50,84 +50,78 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
}
}
// EV, Type, and Egg Group related bait effects
// EV related bait effects
override fun affectWeight(detail: SpawnDetail, spawnablePosition: SpawnablePosition, weight: Float): Float {
val merged = SpawnBaitUtils.mergeEffects(effects)
val hasRelevantEffects =
merged.any { it.type == Effects.EV } ||
merged.any { it.type == Effects.TYPING } ||
merged.any { it.type == Effects.EGG_GROUP }
if (!hasRelevantEffects) {
return super.affectWeight(detail, spawnablePosition, weight)
}
val pokemonDetail = detail as? PokemonSpawnDetail
?: return super.affectWeight(detail, spawnablePosition, weight)
val detailSpecies = pokemonDetail.pokemon.species
?.let { PokemonSpecies.getByName(it) }
?: return super.affectWeight(detail, spawnablePosition, weight)
val formData = detailSpecies.getForm(pokemonDetail.pokemon.aspects)
var newWeight = weight
var used = false
// if bait exists and any effects are related to EV yields
if (merged.any { it.type == Effects.EV }) {
val evEffect = effects.firstOrNull { it.type == Effects.EV }
val baitEVStat = evEffect?.subcategory?.path?.let { Stats.getStat(it) }
if (merged.any { it.type == Effects.EV }){
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
val baitEVStat = effects.firstOrNull { it.type == Effects.EV }?.subcategory?.path?.let { Stats.getStat(it) }
if (baitEVStat != null) {
val evYieldValue = formData.evYield[baitEVStat]?.toFloat() ?: 0f
used = true
if (evYieldValue <= 0f) {
newWeight = 0f
} else {
LOGGER.debug("Boosted weight value");
if (detailSpecies != null && baitEVStat != null) {
val evYieldValue = detailSpecies.evYield[baitEVStat]?.toFloat() ?: 0f
return when {
evYieldValue > 0 -> {
markUsed()
super.affectWeight(detail, spawnablePosition, weight)
}
else -> {
markUsed()
super.affectWeight(detail, spawnablePosition, 0f)
}
}
}
}
}
// if bait exists and any effects are related to Typing
if (newWeight > 0f && merged.any { it.type == Effects.TYPING }) {
val baitEffect = effects.firstOrNull { it.type == Effects.TYPING }
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
if (merged.any { it.type == Effects.TYPING }){
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
val baitEffect = effects.firstOrNull { it.type == Effects.TYPING }
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
if (baitEffect != null && baitTypingEffect != null) {
val isMatchingType = formData.types.contains(baitTypingEffect)
used = true
if (isMatchingType) {
newWeight *= baitEffect.value.toFloat()
if (detailSpecies != null && baitTypingEffect != null) {
val isMatchingType = detailSpecies.types.contains(baitTypingEffect)
return when {
isMatchingType -> {
markUsed()
super.affectWeight(detail, spawnablePosition, weight * baitEffect.value.toFloat())
}
else -> super.affectWeight(detail, spawnablePosition, weight)
}
}
}
}
// if bait exists and any effects are related to Egg Groups
if (newWeight > 0f && merged.any { it.type == Effects.EGG_GROUP }) {
val eggGroupEffects = effects.filter { it.type == Effects.EGG_GROUP }
if (merged.any { it.type == Effects.EGG_GROUP }) {
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
val matchingEffect = eggGroupEffects.firstOrNull { effect ->
val key = effect.subcategory?.path ?: return@firstOrNull false
val eggGroup = EggGroup.fromIdentifier(key)
if (eggGroup == null) {
LOGGER.warn("Unknown egg group identifier: $key")
return@firstOrNull false
if (detailSpecies != null) {
// Collect all the egg group effects
val eggGroupEffects = effects.filter { it.type == Effects.EGG_GROUP }
// Check if any of the egg group effects match the species' egg groups
val matchingEffect = eggGroupEffects.firstOrNull { effect ->
val effectEggGroupKey = effect.subcategory?.path ?: return@firstOrNull false
val eggGroup = EggGroup.fromIdentifier(effectEggGroupKey)
if (eggGroup == null) {
LOGGER.warn("Unknown egg group identifier: $effectEggGroupKey")
return@firstOrNull false
}
detailSpecies.eggGroups.contains(eggGroup)
}
if (matchingEffect != null) {
markUsed()
val multiplier = matchingEffect.value
return super.affectWeight(detail, spawnablePosition, (weight * multiplier).toFloat())
}
}
formData.eggGroups.contains(eggGroup)
}
if (matchingEffect != null) {
used = true
newWeight *= matchingEffect.value.toFloat()
}
}
if (used) markUsed()
return super.affectWeight(detail, spawnablePosition, newWeight)
return super.affectWeight(detail, spawnablePosition, weight)
}
}
@@ -1,86 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.spawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence.Companion.TYPICAL_VARIATION
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.util.mutableLazy
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.item.ItemStack
import com.cobblemon.mod.common.api.spawning.BestSpawner;
import com.cobblemon.mod.common.api.spawning.position.FishingSpawnablePosition
/**
* This isn't really a factory, one FishingSpawner is created as a field on [BestSpawner] on
* server start. However, this emulates the systems that PlayerSpawner uses so extenders can
* add influences that affect all fishing encounters.
*
* Responsible for creating [BasicSpawner]s for Fishing with whatever appropriate settings.
* You can swap over the spawn pool and the influences here, and it will apply to all newly-generated
* [BasicSpawner]s for Fishing. Has a global every-cast influence list, as well as a context-sensitive
* influence list.
*
* @author Andy
* @since January 23rd, 2026
*/
object FishingSpawnerFactory {
var spawnPool: SpawnPool by mutableLazy {
CobblemonSpawnPools.WORLD_SPAWN_POOL
}
data class Context(
val player: ServerPlayer,
val rodStack: ItemStack,
val lureLevel: Int,
val luckOfTheSeaLevel: Int,
val world: ServerLevel,
val pos: BlockPos,
val spawner: BasicSpawner
)
/**
* List of influences for a new cast of the fishing rod. Context is provided at
* build time in [buildPositionInfluences]
*/
var positionInfluenceBuilders = mutableListOf<(ctx: Context) -> SpawningInfluence?>(
{ ctx -> PlayerLevelRangeInfluence(ctx.player, TYPICAL_VARIATION) },
{ ctx -> BucketNormalizingInfluence(tier = ctx.lureLevel + ctx.luckOfTheSeaLevel) }
)
fun createSharedSpawner(): BasicSpawner {
return BasicSpawner(
name = "fishing",
spawnPool = spawnPool
).also { spawner ->
spawner.influences += BucketMultiplyingInfluence(
multipliers = mapOf(
"uncommon" to 2.25f,
"rare" to 5.5f,
"ultra-rare" to 5.5f,
)
)
}
}
/**
* Builds the per-cast influences for [FishingSpawnablePosition]
*/
fun buildPositionInfluences(ctx: Context): MutableList<SpawningInfluence> {
return positionInfluenceBuilders.mapNotNullTo(mutableListOf()) { it(ctx) }
}
}
@@ -1,101 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.spawner
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
import com.cobblemon.mod.common.util.mutableLazy
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
/**
* Responsible for creating [FixedAreaSpawner]s for PokeSnacks with whatever appropriate settings.
* You can swap over the spawn pool and the influences here, and it will apply to all newly-generated
* [FixedAreaSpawner]s for PokeSnacks.
*
* @author Andy
* @since January 23rd, 2026
*/
object PokeSnackSpawnerFactory {
var spawnPool: SpawnPool by mutableLazy {
CobblemonSpawnPools.WORLD_SPAWN_POOL
}
data class Context(
val world: ServerLevel,
val pos: BlockPos,
val horizontalRadius: Int,
val verticalRadius: Int,
val maxPokemonPerChunk: Float,
val name: String,
val baitEffects: List<SpawnBait.Effect>
)
/**
* The list of influences for a new [FixedAreaSpawner] for a PokeSnack.
* The influences will be added to the spawner in the order they are added to this list.
*/
var influenceBuilders = mutableListOf<(ctx: Context) -> SpawningInfluence?>(
{ ctx ->
val stackedLureTier = ctx.baitEffects
.filter { it.type == SpawnBait.Effects.RARITY_BUCKET }
.sumOf { it.value }
.toInt()
if (stackedLureTier <= 0) null else BucketNormalizingInfluence(
tier = stackedLureTier,
gradient = 0.2F,
firstTier = 1.2F
)
},
{ _ ->
BucketMultiplyingInfluence(
mapOf(
"uncommon" to 2.25f,
"rare" to 5.5f,
"ultra-rare" to 5.5f,
)
)
},
{ ctx ->
SpawnBaitInfluence(effects = ctx.baitEffects)
},
)
fun create(ctx: Context): FixedAreaSpawner {
val influences = influenceBuilders.mapNotNull { it(ctx) }
return FixedAreaSpawner(
name = ctx.name,
spawnPool = spawnPool,
world = ctx.world,
position = ctx.pos,
horizontalRadius = ctx.horizontalRadius,
verticalRadius = ctx.verticalRadius,
maxPokemonPerChunk = ctx.maxPokemonPerChunk
).also { spawner ->
spawner.influences.addAll(influences)
// TODO(Andy): PokeSnacks currently bypass pokemon spawn rules, should that be true?
// Adding this rule will change that
spawner.influences.addAll(
CobblemonSpawnRules.rules.values
.filter(SpawnRule::enabled)
.flatMap(SpawnRule::components)
)
}
}
}
@@ -8,58 +8,30 @@
package com.cobblemon.mod.common.api.stats
import com.cobblemon.mod.common.Cobblemon
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.stats.StatFormatter
object CobblemonStats {
val stats = mutableMapOf<String, CobblemonStat>()
val stats = mutableMapOf<String, ResourceLocation>()
@JvmField
var CAPTURED: CobblemonStat = CobblemonStat("captured")
@JvmField
val SHINIES_CAPTURED: CobblemonStat = CobblemonStat("shinies_captured")
@JvmField
val RELEASED: CobblemonStat = CobblemonStat("released")
@JvmField
val EVOLVED: CobblemonStat = CobblemonStat("evolved")
@JvmField
val LEVEL_UP: CobblemonStat = CobblemonStat("level_up")
@JvmField
val BATTLES_WON: CobblemonStat = CobblemonStat("battles_won")
@JvmField
val BATTLES_LOST: CobblemonStat = CobblemonStat("battles_lost")
@JvmField
val BATTLES_FLED: CobblemonStat = CobblemonStat("battles_fled")
@JvmField
val BATTLES_TOTAL: CobblemonStat = CobblemonStat("battles_total")
@JvmField
val DEX_ENTRIES: CobblemonStat = CobblemonStat("dex_entries")
@JvmField
val EGGS_COLLECTED: CobblemonStat = CobblemonStat("eggs_collected")
@JvmField
val EGGS_HATCHED: CobblemonStat = CobblemonStat("eggs_hatched")
@JvmField
val TRADED: CobblemonStat = CobblemonStat("traded")
@JvmField
val FOSSILS_REVIVED: CobblemonStat = CobblemonStat("fossils_revived")
@JvmField
val TIMES_RIDDEN: CobblemonStat = CobblemonStat("times_ridden")
@JvmField
val ROD_CASTS: CobblemonStat = CobblemonStat("rod_casts")
@JvmField
val REEL_INS: CobblemonStat = CobblemonStat("reel_ins")
@JvmField
val POKEMON_INTERACTED_WITH: CobblemonStat = CobblemonStat("pokemon_interacted_with")
@JvmField
val RIDING_LAND: CobblemonStat = CobblemonStat("riding_land", StatFormatter.DISTANCE)
@JvmField
val RIDING_AIR: CobblemonStat = CobblemonStat("riding_air", StatFormatter.DISTANCE)
@JvmField
val RIDING_LIQUID: CobblemonStat = CobblemonStat("riding_liquid", StatFormatter.DISTANCE)
//TODO block, stats (interact, gimmi)
var CAPTURED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "captured") //makeCustomStat("captured", StatFormatter.DEFAULT)
val SHINIES_CAPTURED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "shinies_captured") //makeCustomStat("shinies_captured", StatFormatter.DEFAULT)
val RELEASED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "released") //makeCustomStat("released", StatFormatter.DEFAULT)
val EVOLVED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "evolved") //makeCustomStat("evolved", StatFormatter.DEFAULT)
val LEVEL_UP: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "level_up") //makeCustomStat("level_up", StatFormatter.DEFAULT)
val BATTLES_WON: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_won") //makeCustomStat("battles_won", StatFormatter.DEFAULT)
val BATTLES_LOST: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_lost") //makeCustomStat("battles_lost", StatFormatter.DEFAULT)
val BATTLES_FLED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_fled") //makeCustomStat("battles_fled", StatFormatter.DEFAULT)
val BATTLES_TOTAL: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_total") //makeCustomStat("battles_total", StatFormatter.DEFAULT)
val DEX_ENTRIES: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "dex_entries") //makeCustomStat("dex_entries", StatFormatter.DEFAULT)
val EGGS_COLLECTED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "eggs_collected") //makeCustomStat("eggs_collected", StatFormatter.DEFAULT)
val EGGS_HATCHED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "eggs_hatched") //makeCustomStat("eggs_hatched", StatFormatter.DEFAULT)
val TRADED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "traded") //makeCustomStat("traded", StatFormatter.DEFAULT)
val FOSSILS_REVIVED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "fossils_revived") //makeCustomStat("fossils_revived", StatFormatter.DEFAULT)
val TIMES_RIDDEN: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "times_ridden")
val ROD_CASTS: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "rod_casts")
val REEL_INS: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "reel_ins")
val POKEMON_INTERACTED_WITH: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "pokemon_interacted_with") //makeCustomStat("pokemon_interacted_with", StatFormatter.DEFAULT)
//TODO block, stats (interact, gimmi), riding (styles?)
fun registerStats() {
stats["captured"] = CAPTURED
@@ -80,22 +52,5 @@ object CobblemonStats {
stats["rod_casts"] = ROD_CASTS
stats["reel_ins"] = REEL_INS
stats["pokemon_interacted_with"] = POKEMON_INTERACTED_WITH
stats["riding_land"] = RIDING_LAND
stats["riding_air"] = RIDING_AIR
stats["riding_liquid"] = RIDING_LIQUID
}
@JvmStatic
fun getStat(cobblemonStat: CobblemonStat) : ResourceLocation {
val resourceLocation = cobblemonStat.resourceLocation
val stat = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation)
if (stat == null) {
Cobblemon.LOGGER.error("Could not find stat with id {}", resourceLocation)
}
return stat ?: throw NullPointerException("Could not find stat with id $resourceLocation")
}
data class CobblemonStat(val path: String, val formatter: StatFormatter = StatFormatter.DEFAULT) {
val resourceLocation: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", path);
}
}
@@ -88,6 +88,7 @@ abstract class OneToOneFileStoreAdapter<S>(
result
}
else {
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
var result = storeClass.getConstructor(UUID::class.java).newInstance(uuid)
save(storeClass, uuid, serialize(result, registryAccess))
oldFile.delete()
@@ -258,22 +258,17 @@ open class PartyStore(override val uuid: UUID) : PokemonStore<PartyPosition>() {
@JvmOverloads
fun toBattleTeam(clone: Boolean = false, healPokemon: Boolean = false, leadingPokemon: UUID? = null) : List<BattlePokemon> {
var leadingPokemonId = leadingPokemon
val result = this.mapNotNull {
return@mapNotNull if (clone) {
BattlePokemon.safeCopyOf(it).also { copy ->
if (leadingPokemon != null && it.uuid == leadingPokemonId) {
leadingPokemonId = copy.uuid
}
}
BattlePokemon.safeCopyOf(it)
} else {
BattlePokemon.playerOwned(it)
}.also { if (healPokemon) it.effectedPokemon.heal() }
}.toMutableList()
// reposition lead to front of the party
if (leadingPokemonId != null && result.first().uuid != leadingPokemonId) {
result.find { it.uuid == leadingPokemonId }?.let { lead ->
if (leadingPokemon != null && result.first().uuid != leadingPokemon) {
result.find { it.uuid == leadingPokemon }?.let { lead ->
result.remove(lead)
result.add(0, lead)
}
@@ -154,12 +154,12 @@ open class PlayerPartyStore(
// Metabolism for Fullness
if (pokemon.currentFullness > 0) {
pokemon.tickMetabolism(20)
pokemon.tickMetabolism()
}
// Interaction Cooldown
if (pokemon.interactionCooldowns.any()) {
pokemon.tickInteractionCooldown(20)
pokemon.tickInteractionCooldown()
}
pokemon.features.filterIsInstance<TickingSpeciesFeature>().forEach { it.onSecondPassed(player.serverLevel(), pokemon, null) }
@@ -28,7 +28,6 @@ data class GeneralPlayerData(
var starterUUID: UUID?,
var keyItems: MutableSet<ResourceLocation>,
var battleTheme: ResourceLocation?,
var partySelectTutorialDone: Boolean = false,
val extraData: MutableMap<String, PlayerDataExtension>,
) : InstancedPlayerData {
var advancementData: PlayerAdvancementData = PlayerAdvancementData()
@@ -54,8 +53,7 @@ data class GeneralPlayerData(
starterSelected,
starterUUID,
advancementData.totalBattleVictoryCount == 0,
battleTheme,
partySelectTutorialDone
battleTheme
)
}
@@ -36,8 +36,7 @@ class PlayerDataJsonBackend: JsonBackedPlayerDataStoreBackend<GeneralPlayerData>
starterUUID = null,
keyItems = Cobblemon.config.defaultKeyItems,
extraData = mutableMapOf(),
battleTheme = CobblemonSounds.PVP_BATTLE.location,
partySelectTutorialDone = false
battleTheme = CobblemonSounds.PVP_BATTLE.location
)}
override val gson = GsonBuilder()
@@ -37,8 +37,7 @@ class PlayerDataMongoBackend(mongoClient: MongoClient, databaseName: String, col
starterUUID = null,
keyItems = Cobblemon.config.defaultKeyItems,
extraData = mutableMapOf(),
battleTheme = CobblemonSounds.PVP_BATTLE.location,
partySelectTutorialDone = false
battleTheme = CobblemonSounds.PVP_BATTLE.location
)}
override val gson = GsonBuilder()
@@ -34,8 +34,7 @@ data class ClientGeneralPlayerData(
var starterSelected: Boolean = false,
var starterUUID: UUID? = null,
var showChallengeLabel: Boolean = true,
val battleTheme: ResourceLocation? = null,
var partySelectTutorialDone: Boolean = false
val battleTheme: ResourceLocation? = null
) : ClientInstancedPlayerData {
override fun encode(buf: RegistryFriendlyByteBuf) {
@@ -47,7 +46,6 @@ data class ClientGeneralPlayerData(
buf.writeNullable(starterUUID) { pb, value -> pb.writeString(value.toString()) }
buf.writeNullable(resetStarters) { pb, value -> pb.writeBoolean(value) }
buf.writeNullable(battleTheme) {pb, value -> pb.writeIdentifier(value)}
buf.writeBoolean(partySelectTutorialDone)
}
companion object {
fun decode(buffer: RegistryFriendlyByteBuf): SetClientPlayerDataPacket {
@@ -59,7 +57,6 @@ data class ClientGeneralPlayerData(
val starterUUID = buffer.readNullable { it.readString() }?.let { UUID.fromString(it) }
val resetStarterPrompt = buffer.readNullable { it.readBoolean() }
val battleTheme = buffer.readNullable { it.readIdentifier() }
val partySelectTutorialDone = buffer.readBoolean()
val data = ClientGeneralPlayerData(
resetStarterPrompt,
promptStarter,
@@ -67,8 +64,7 @@ data class ClientGeneralPlayerData(
starterSelected,
starterUUID,
showChallengeLabel,
battleTheme,
partySelectTutorialDone
battleTheme
)
//Weird to do this, but since the flag doesn't get passed to the decoded obj, do it here
//Should be fine, as long as decode doesn't get run on the server for some reason
@@ -42,7 +42,6 @@ object CobblemonItemTags {
@JvmField val DAWN_STONE_ORES = create("dawn_stone_ores")
@JvmField val POTTERY_SHERDS = create("decorated_pot_sherds")
@JvmField val DEEP_SEAS = create("deep_seas")
@JvmField val DISPLAY_CASE_ITEMS = create("display_case_items")
@JvmField val DUSK_STONE_ORES = create("dusk_stone_ores")
@JvmField val ETHERS = create("ethers")
@JvmField val EVOLUTION_ITEMS = create("evolution_items")
@@ -58,7 +57,6 @@ object CobblemonItemTags {
@JvmField val HANGING_SIGNS = create("hanging_signs")
@JvmField val HERBS = create("herbs")
@JvmField val ICE_STONE_ORES = create("ice_stone_ores")
@JvmField val ITEM_BLOCKS = create("item_blocks")
@JvmField val LEAF_STONE_ORES = create("leaf_stone_ores")
@JvmField val MACHINES = create("machines")
@JvmField val MINT_LEAF = create("mint_leaf")
@@ -67,7 +65,6 @@ object CobblemonItemTags {
@JvmField val MOCHIS = create("mochis")
@JvmField val MOON_STONE_ORES = create("moon_stone_ores")
@JvmField val MUTATED_BERRIES = create("mutated_berries")
@JvmField val PLAQUES = create("plaques")
@JvmField val PLANTS = create("plants")
@JvmField val POKE_BALLS = create("poke_balls")
@JvmField val POKE_RODS = create("poke_rods")
@@ -63,8 +63,8 @@ object BattleBuilder {
): BattleStartResult {
val adjustLevel = battleFormat.adjustLevel
val team1 = partyAccessor(player1).toBattleTeam(clone = cloneParties || adjustLevel > 0, healPokemon = healFirst, leadingPokemonPlayer1)
val team2 = partyAccessor(player2).toBattleTeam(clone = cloneParties || adjustLevel > 0, healPokemon = healFirst, leadingPokemonPlayer2)
val team1 = partyAccessor(player1).toBattleTeam(clone = cloneParties || adjustLevel > 0, healPokemon = healFirst, leadingPokemonPlayer1).sortedBy { it.health <= 0 }
val team2 = partyAccessor(player2).toBattleTeam(clone = cloneParties || adjustLevel > 0, healPokemon = healFirst, leadingPokemonPlayer2).sortedBy { it.health <= 0 }
val battlePartyStores = mutableListOf<PlayerPartyStore>()
@@ -105,18 +105,12 @@ data class BattleFormat(
}
fun toFormatJSON(): String {
/*
Bag clause does not exist in showdown as a rule because showdown simply has no concept of a 'bag'.
If we try sending it, the battle will error. So this simply omits that from ever getting sent.
If we ever find a case where we are doing this for more than just bag clause, we should make a proper abstraction.
*/
val rulesToSendToShowdown = ruleSet.filter { it != BattleRules.BAG_CLAUSE }
return """
{
"mod": "$mod",
"gameType": "${battleType.name}",
"gen": $gen,
"ruleset": [${rulesToSendToShowdown.joinToString { "\"$it\"" }}],
"ruleset": [${ruleSet.joinToString { "\"$it\"" }}],
"effectType": "Format"
}
""".trimIndent().replace("\n", "")
@@ -221,7 +221,6 @@ object BattleRegistry {
fun closeBattle(battle: PokemonBattle) {
battle.onEndHandlers.forEach { it(battle) }
battleMap.remove(battle.battleId)
ShowdownService.service.endBattle(battle)
}
@JvmStatic
@@ -12,7 +12,6 @@ object BattleRules {
const val OBTAINABLE = "Obtainable"
const val PAST = "+Past"
const val UNOBTAINABLE = "+Unobtainable"
const val BAG_CLAUSE = "Bag Clause"
const val TEAM_PREVIEW = "Team Preview"
const val ENDLESS_BATTLE_CLAUSE = "Endless Battle Clause"
const val CANCEL_MOD = "Cancel Mod"
@@ -94,8 +94,7 @@ enum class ShowdownActionResponseType(val loader: (RegistryFriendlyByteBuf) -> S
PASS({ PassActionResponse }),
SHIFT({ ShiftActionResponse()}),
HEAL_ITEM({ HealItemActionResponse("potion") }),
FORFEIT({ ForfeitActionResponse() }),
FLEE_ATTEMPT({ FleeAttemptActionResponse() }),
FORFEIT({ ForfeitActionResponse() });
}
abstract class ShowdownActionResponse(val type: ShowdownActionResponseType) {
@@ -281,11 +280,6 @@ class ForfeitActionResponse : ShowdownActionResponse(ShowdownActionResponseType.
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?) = "forfeit"
}
class FleeAttemptActionResponse : ShowdownActionResponse(ShowdownActionResponseType.FLEE_ATTEMPT) {
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean) = true
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?) = "flee-attempt"
}
class ShowdownMoveset {
lateinit var moves: List<InBattleMove>
var trapped = false
@@ -295,8 +289,6 @@ class ShowdownMoveset {
var canDynamax = false
var maxMoves: List<InBattleGimmickMove?>? = null
var canTerastallize: String? = null
/** This stores a list of gimmicks that have already been used this turn by a previous Pokemon, but the full turn has not been processed (ie. double battles). */
val pendingGimmickUsedThisTurn = mutableListOf<Gimmick>()
fun saveToBuffer(buffer: RegistryFriendlyByteBuf) {
buffer.writeSizedInt(IntSize.U_BYTE, moves.size)
@@ -300,35 +300,4 @@ object ShowdownInterpreter {
} ?:
MissingContext()
}
/**
* Registers a new update instruction parser.
* @param id The ID of the instruction to register.
* @param callback The callback function to create the instruction.
*/
@JvmStatic
fun registerUpdateInstructionParser(id: String, callback: (PokemonBattle, InstructionSet, BattleMessage, Iterator<BattleMessage>) -> InterpreterInstruction) {
updateInstructionParser[id] = callback
}
/**
* Registers a new split instruction parser.
* @param id The ID of the instruction to register.
* @param callback The callback function to create the instruction.
*/
@JvmStatic
fun registerSplitInstructionParser(id: String, callback: (PokemonBattle, BattleActor, InstructionSet, BattleMessage, BattleMessage, Iterator<BattleMessage>) -> InterpreterInstruction) {
splitInstructionParser[id] = callback
}
/**
* Registers a new side instruction parser.
* @param id The ID of the instruction to register.
* @param callback The callback function to create the instruction.
*/
@JvmStatic
fun registerSideInstructionParser(id: String, callback: (PokemonBattle, BattleActor, InstructionSet, BattleMessage) -> InterpreterInstruction) {
sideInstructionParser[id] = callback
}
}
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.battles
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.battles.runner.ShowdownService
import net.minecraft.CrashReport
import java.util.*
import java.util.concurrent.CountDownLatch
@@ -38,15 +37,8 @@ class ShowdownThread : Thread("Cobblemon Showdown") {
override fun run() {
LOGGER.info("Starting showdown service...")
try {
ShowdownService.service.openConnection()
LOGGER.info("Showdown has been started!")
} catch (e: Exception) {
LOGGER.error("Failed to start showdown service!", e)
} finally {
this.latch.countDown()
throw RuntimeException("Showdown service failed to initialize...")
}
ShowdownService.service.openConnection()
LOGGER.info("Showdown has been started!")
this.latch.countDown()
}
}
@@ -18,7 +18,7 @@ import java.util.UUID
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.Component
open class MultiPokemonBattleActor(
class MultiPokemonBattleActor(
pokemonList: List<BattlePokemon>,
artificialDecider: BattleAI = RandomBattleAI(),
uuid: UUID = UUID.randomUUID()
@@ -24,14 +24,17 @@ import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.Component
import net.minecraft.world.phys.Vec3
open class PokemonBattleActor(
class PokemonBattleActor(
uuid: UUID,
val pokemon: BattlePokemon,
override val fleeDistance: Float,
artificialDecider: BattleAI = RandomBattleAI(),
artificialDecider: BattleAI = RandomBattleAI()
) : AIBattleActor(uuid, listOf(pokemon), artificialDecider), EntityBackedBattleActor<PokemonEntity>, FleeableBattleActor {
override val initialPos: Vec3? = pokemon.entity?.position()
override val initialPos: Vec3?
init {
initialPos = entity?.position()
}
override fun getName() = pokemon.effectedPokemon.species.translatedName
override fun nameOwned(name: String): MutableComponent = Component.literal(name)
override fun getWorldAndPosition(): Pair<ServerLevel, Vec3>? {
@@ -17,7 +17,7 @@ import com.cobblemon.mod.common.util.battleLang
import java.util.UUID
import net.minecraft.network.chat.MutableComponent
open class TrainerBattleActor(
class TrainerBattleActor(
val trainerName: String,
uuid: UUID,
pokemonList: List<BattlePokemon>,
@@ -48,7 +48,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
private val hpWeightConsideration = 0.25 // how much HP difference is a consideration for switchins
private val hpFractionCoefficient = 0.4 // how much HP differences should be taken into account for switch ins
private val boostWeightCoefficient = 1 // the amount of boosts considered a baseline to be removed
private val switchOutMatchupThreshold = -2 // todo change this to get it feeling just right (-7 never switches)
private val switchOutMatchupThreshold = 0 // todo change this to get it feeling just right (-7 never switches)
private val selfKoMoveMatchupThreshold = 0.3
private val trickRoomThreshold = 85
private val recoveryMoveThreshold = 0.50
@@ -218,14 +218,19 @@ class StrongBattleAI(skill: Int) : BattleAI {
.filter { it.second.canBeSentOut() }
if (forceSwitch || activeBattlePokemon.isGone()) {
// When forced to switch, pick the Pokemon with the best matchup estimation
val bestSwitchScore = availableSwitches.maxOfOrNull { estimateMatchup(activeBattlePokemon, aiSide, battle, it.first) }
?: return PassActionResponse
val bestSwitch = availableSwitches.firstOrNull { estimateMatchup(activeBattlePokemon, aiSide, battle, it.first) == bestSwitchScore }
?: return PassActionResponse
if (battle.turn == 1) {
val switchTo = activeBattlePokemon.actor.pokemonList.filter { it.canBeSentOut() }.randomOrNull()
?: return DefaultActionResponse()
switchTo.willBeSwitchedIn = true
return SwitchActionResponse(switchTo.uuid)
}
else {
val bestEstimation = availableSwitches.maxByOrNull { estimateMatchup(activeBattlePokemon, aiSide, battle, it.first) }
?: return PassActionResponse
bestSwitch.second.willBeSwitchedIn = true
return SwitchActionResponse(bestSwitch.second.uuid)
bestEstimation.second.willBeSwitchedIn = true
return SwitchActionResponse(bestEstimation.second.uuid)
}
}
if (moveset == null) {
return PassActionResponse
@@ -253,9 +258,9 @@ class StrongBattleAI(skill: Int) : BattleAI {
if (!checkSkillLevel()){
val move = availableMoves
.filter { it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
.randomOrNull()
?: return MoveActionResponse("struggle")
.filter { it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
.randomOrNull()
?: return MoveActionResponse("struggle")
return chooseMove(move.first, activeBattlePokemon)
}
@@ -264,11 +269,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
if (checkSwitchOutSkill() && shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
considerSwitching(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, availableSwitches, battle, aiSide)
}
// If HP is below 30% and not switching out, always use the most damaging move
if (activeTrackerPokemon.currentHpPercent < 0.3 && !shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
findAndUseMostDamagingMove(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, moveset, battle, aiSide)?.let { return it }
}
activeTrackerPokemon.firstTurn = false
// Decision-making based on move availability and switch-out condition
if (!shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
@@ -289,6 +290,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
return chooseMove(fakeOut.first, activeBattlePokemon, targets.firstOrNull { validTarget != null && validTarget.id == it.battlePokemon!!.uuid})
}
activeTrackerPokemon.firstTurn = false
// Explosion/Self destruct
availableMoves.firstOrNull {
@@ -306,7 +309,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
// Deal with non-weather related field changing effects
for (move in availableMoves) {
// Tailwind
if (move.first.id == "tailwind" && move.first.id != activeTracker.alliedSide.tailwindCondition &&
availableSwitches.size > 2) {
@@ -315,21 +318,21 @@ class StrongBattleAI(skill: Int) : BattleAI {
// Trick room
if (move.first.id == "trickroom" && move.first.id != activeTracker.currentRoom
&& availableSwitches.count { statEstimationActive(it.first, Stats.SPEED) <= trickRoomThreshold } >= 2) {
&& availableSwitches.count { statEstimationActive(it.first, Stats.SPEED) <= trickRoomThreshold } >= 2) {
return chooseMove(move.first, activeBattlePokemon)
}
// todo find a way to get list of active screens
// Aurora veil
if (move.first.id == "auroraveil" && move.first.id != activeTracker.alliedSide.screenCondition
&& activeTracker.currentWeather in listOf("hail", "snow")) {
&& activeTracker.currentWeather in listOf("hail", "snow")) {
return chooseMove(move.first, activeBattlePokemon)
}
// todo find a way to get list of active screens
// Light Screen
if (move.first.id == "lightscreen" && move.first.id != activeTracker.alliedSide.screenCondition
&& opponents.any { (it.species?.baseStats?.get(Stats.SPECIAL_ATTACK) ?: 0) > (it.species?.baseStats?.get(Stats.ATTACK) ?: 0) }
&& opponents.any { (it.species?.baseStats?.get(Stats.SPECIAL_ATTACK) ?: 0) > (it.species?.baseStats?.get(Stats.ATTACK) ?: 0) }
&& availableSwitches.size > 1) {
return chooseMove(move.first, activeBattlePokemon)
}
@@ -347,13 +350,13 @@ class StrongBattleAI(skill: Int) : BattleAI {
for (move in availableMoves) {
// Setup
if (nOppRemainingMons >= 3 && move.first.id in AIUtility.entryHazards
&& !activeTracker.opponentSide.sideHazards.contains(move.first.id)) {
&& !activeTracker.opponentSide.sideHazards.contains(move.first.id)) {
return chooseMove(move.first, activeBattlePokemon)
}
// Removal
if (nRemainingMons >= 2 && move.first.id in AIUtility.antiHazardsMoves
&& activeTracker.alliedSide.sideHazards.isNotEmpty()) {
&& activeTracker.alliedSide.sideHazards.isNotEmpty()) {
return chooseMove(move.first, activeBattlePokemon)
}
}
@@ -363,10 +366,10 @@ class StrongBattleAI(skill: Int) : BattleAI {
// Court Change
for (move in availableMoves) {
if (move.first.id == "courtchange"
&& (!AIUtility.entryHazards.none { it in activeTracker.alliedSide.sideHazards }
|| setOf("tailwind", "lightscreen", "reflect").any { it in activeTracker.opponentSide.sideHazards })
&& setOf("tailwind", "lightscreen", "reflect").none { it in activeTracker.opponentSide.sideHazards }
&& AIUtility.entryHazards.none { it in activeTracker.opponentSide.sideHazards }) {
&& (!AIUtility.entryHazards.none { it in activeTracker.alliedSide.sideHazards }
|| setOf("tailwind", "lightscreen", "reflect").any { it in activeTracker.opponentSide.sideHazards })
&& setOf("tailwind", "lightscreen", "reflect").none { it in activeTracker.opponentSide.sideHazards }
&& AIUtility.entryHazards.none { it in activeTracker.opponentSide.sideHazards }) {
return chooseMove(move.first, activeBattlePokemon)
}
}
@@ -374,7 +377,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
// Strength Sap
for (move in availableMoves) {
if (move.first.id == "strengthsap" && activeTrackerPokemon.currentHpPercent < 0.5
&& activeTrackerPokemon.species!!.baseStats.getOrDefault(Stats.ATTACK, 0) > 80) {
&& activeTrackerPokemon.species!!.baseStats.getOrDefault(Stats.ATTACK, 0) > 80) {
return chooseMove(move.first, activeBattlePokemon)
}
}
@@ -382,10 +385,10 @@ class StrongBattleAI(skill: Int) : BattleAI {
// Belly Drum
for (move in availableMoves) {
if (move.first.id == "bellydrum"
&& (activeTrackerPokemon.currentHpPercent > 0.6
&& activeTrackerPokemon.pokemon!!.heldItem().item == CobblemonItems.SITRUS_BERRY
|| activeTrackerPokemon.currentHpPercent > 0.8)
&& activeTrackerPokemon.boosts.getOrDefault(Stats.ATTACK, 0) < 1) {
&& (activeTrackerPokemon.currentHpPercent > 0.6
&& activeTrackerPokemon.pokemon!!.heldItem().item == CobblemonItems.SITRUS_BERRY
|| activeTrackerPokemon.currentHpPercent > 0.8)
&& activeTrackerPokemon.boosts.getOrDefault(Stats.ATTACK, 0) < 1) {
return chooseMove(move.first, activeBattlePokemon)
}
}
@@ -395,8 +398,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
for (move in availableMoves) {
AIUtility.weatherSetupMoves[move.first.id]?.let { requiredWeather ->
if (activeTracker.currentWeather != requiredWeather.lowercase() &&
!(activeTracker.currentWeather == "primordialsea" && requiredWeather == "raindance") &&
!(activeTracker.currentWeather == "desolateland" && requiredWeather == "sunnyday")) {
!(activeTracker.currentWeather == "primordialsea" && requiredWeather == "raindance") &&
!(activeTracker.currentWeather == "desolateland" && requiredWeather == "sunnyday")) {
return chooseMove(move.first, activeBattlePokemon)
}
}
@@ -422,8 +425,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
// Stall out side conditions
if ((activeTracker.opponentSide.screenCondition != null || activeTracker.opponentSide.tailwindCondition != null) &&
(activeTracker.alliedSide.screenCondition == null || activeTracker.alliedSide.tailwindCondition == null) ||
opponents.any { it.currentStatus == null } &&
activeTrackerPokemon.protectCount == 0 && opponents.none { it.currentAbility?.name == "unseenfist"}) {
opponents.any { it.currentStatus == null } &&
activeTrackerPokemon.protectCount == 0 && opponents.none { it.currentAbility?.name == "unseenfist"}) {
activeTrackerPokemon.protectCount = 3
return chooseMove(move.first, activeBattlePokemon)
}
@@ -451,10 +454,10 @@ class StrongBattleAI(skill: Int) : BattleAI {
activeTrackerPokemon.firstTurn = false
val move = availableMoves
.filter { it.first.canBeUsed() }
.filter { it.first.mustBeUsed() || it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
.randomOrNull()
?: return MoveActionResponse("struggle")
.filter { it.first.canBeUsed() }
.filter { it.first.mustBeUsed() || it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
.randomOrNull()
?: return MoveActionResponse("struggle")
return chooseMove(move.first, activeBattlePokemon)
}
@@ -511,10 +514,6 @@ class StrongBattleAI(skill: Int) : BattleAI {
return false
val activeTrackerPokemon = activeTracker.alliedSide.activePokemon.first { it.id == activeBattlePokemon.battlePokemon!!.uuid }
// Don't switch out if we just switched in
if (activeTrackerPokemon.firstTurn)
return false
val actorTracker = activeTracker.alliedSide.actors.first { activeTrackerPokemon in it.activePokemon }
val availableSwitches = actorTracker.party.filter { it.currentHp!! > 0 }
val currentAbility = activeTrackerPokemon.pokemon!!.ability
@@ -522,19 +521,6 @@ class StrongBattleAI(skill: Int) : BattleAI {
val opponentActiveTracker = activeTracker.opponentSide.activePokemon
val opponentSpeedEstimations = opponentActiveTracker.map { statEstimationActive(it, Stats.SPEED) }
// Only switch if a switch-in is significantly better than the current Pokémon
val currentScore = estimateMatchup(activeBattlePokemon, side, battle)
val bestSwitchScore = availableSwitches.maxOfOrNull { estimateMatchup(activeBattlePokemon, side, battle, it) } ?: currentScore
val improvementThreshold = currentScore.absoluteValue * 0.5 + 3
if (bestSwitchScore <= currentScore + improvementThreshold) {
return false
}
if(bestSwitchScore < 1) {
return false
}
// todo add some way to keep track of the player's boosting to see if it needs to switch out to something that can stop it
// if slower speed stat than the opposing pokemon and HP is less than 20% don't switch out
@@ -562,8 +548,6 @@ class StrongBattleAI(skill: Int) : BattleAI {
if (availableSwitches.isEmpty() || availableSwitches.none { estimateMatchup(activeBattlePokemon, side, battle, it) > 0 })
return false
// ...and a 'good' reason to switch out
if (opponentActiveTracker.any { it.boosts.getOrDefault(Stats.ACCURACY, 0) <= accuracySwitchThreshold } ||
opponentActiveTracker.any { it.boosts.getOrDefault(Stats.DEFENCE, 0) <= -3 } ||
@@ -990,4 +974,6 @@ class StrongBattleAI(skill: Int) : BattleAI {
return MoveActionResponse(move.id, chosenTarget.getPNX())
}
}
}
}
@@ -132,7 +132,6 @@ class TrackerActor(val uuid: UUID) {
actor.activePokemon.filter { newActive -> activePokemon.none { it.id == newActive.battlePokemon?.uuid } }.forEach {
val active = party.firstOrNull { trackMon -> trackMon.id == it.battlePokemon?.uuid } ?: return@forEach
party.remove(active)
active.firstTurn = true // Reset firstTurn when switching in
activePokemon.add(active)
}
val swappedOut = activePokemon.filter { trackMon -> actor.activePokemon.none { it.battlePokemon?.uuid == trackMon.id } }
@@ -146,7 +145,6 @@ class TrackerActor(val uuid: UUID) {
actor.activePokemon.filter { newActive -> activePokemon.none { it.id == newActive.battlePokemon?.uuid } }.forEach {
val active = party.firstOrNull { trackMon -> trackMon.id == it.battlePokemon?.uuid } ?: return@forEach
party.remove(active)
active.firstTurn = true // Reset firstTurn when switching in
activePokemon.add(active)
}
val swappedOut = activePokemon.filter { trackMon -> actor.activePokemon.none { it.battlePokemon?.uuid == trackMon.id } }
@@ -114,14 +114,7 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
}
"maxguard", "protect" -> battleLang("activate.protect", pokemonName)
"shadowforce", "hyperspacefury", "hyperspacehole" -> battleLang("activate.phantomforce", pokemonName)
else -> {
val msgVariant = message.optionalArgument("msg")
if (msgVariant != null) {
battleLang("activate.${effect.id}.$msgVariant", pokemonName, sourceName, extraEffect)
} else {
battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
}
}
else -> battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
}
battle.broadcastChatMessage(lang)
//We check holds here so the chat msg + particle effect happen more concurrently, instead of sequentially
@@ -51,9 +51,8 @@ class FaintInstruction(battle: PokemonBattle, val message: BattleMessage) : Inte
preamble.thenAccept {
faintingPokemon.effectedPokemon.currentHealth = 0
faintingPokemon.faintedAt = battle.faintCounter++
faintingPokemon.sendUpdate()
CobblemonEvents.BATTLE_FAINTED.post(BattleFaintedEvent(battle, pokemon, context, pnx))
CobblemonEvents.BATTLE_FAINTED.post(BattleFaintedEvent(battle, pokemon, context))
battle.getActorAndActiveSlotFromPNX(pnx).second.battlePokemon = null
faintingPokemon.contextManager.add(context)
faintingPokemon.contextManager.clear(BattleContext.Type.STATUS, BattleContext.Type.VOLATILE, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
@@ -26,7 +26,6 @@ import com.cobblemon.mod.common.util.battleLang
class FormeChangeInstruction(val message: BattleMessage): InterpreterInstruction {
override fun invoke(battle: PokemonBattle) {
val (pnx, _) = message.pnxAndUuid(0) ?: return
val battlePokemon = message.battlePokemon(0, battle) ?: return
val details = message.argumentAt(1)?.split(',')?.get(0)?.lowercase() ?: return
val speciesName = details.substringBefore('-')
@@ -38,7 +37,7 @@ class FormeChangeInstruction(val message: BattleMessage): InterpreterInstruction
battle.dispatchWaiting {
battle.minorBattleActions[battlePokemon.uuid] = message
CobblemonEvents.FORME_CHANGE.post(FormeChangeEvent(battle, battlePokemon, formName, pnx))
CobblemonEvents.FORME_CHANGE.post(FormeChangeEvent(battle, battlePokemon, formName))
val pokemonName = battlePokemon.getName()
val lang = when(formName) {
"busted", "hero", "complete" -> return@dispatchWaiting
@@ -166,11 +166,6 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
// If we can't find the entity for some reason then we're going to skip the recall animation
val sendOutFuture = CompletableFuture<Unit>()
(pokemonEntity?.recallWithAnimation() ?: CompletableFuture.completedFuture(Unit)).thenApply {
if (battle.ended) {
sendOutFuture.complete(Unit)
return@thenApply
}
// Queue actual swap and send-in after the animation has ended
actor.pokemonList.swap(actor.activePokemon.indexOf(activePokemon), actor.pokemonList.indexOf(newPokemon))
activePokemon.battlePokemon = newPokemon
@@ -43,17 +43,17 @@ class WinInstruction(val message: BattleMessage): InterpreterInstruction {
val losersText = losers.map { it.getName() }.reduce { acc, next -> acc + " & " + next }
val wasCaught = battle.showdownMessages.any { "capture" in it }
// If the battle was a PvW battle, we need to set the killer of the wild Pokémon to the player
if (battle.isPvW) {
val nonPlayerActor = battle.actors.first { it.type == ActorType.WILD }
val wildPokemon: BattlePokemon = nonPlayerActor.pokemonList.first()
if (!wasCaught && losers.any { it.uuid == wildPokemon.uuid }) {
wildPokemon.effectedPokemon.entity?.killer = (battle.actors.firstOrNull { it.type == ActorType.PLAYER } as? PlayerBattleActor)?.entity
}
}
battle.dispatch {
// If the battle was a PvW battle, we need to set the killer of the wild Pokémon to the player
if (battle.isPvW) {
val nonPlayerActor = battle.actors.first { it.type == ActorType.WILD }
val wildPokemon: BattlePokemon = nonPlayerActor.pokemonList.first()
if (!wasCaught && losers.any { it.uuid == wildPokemon.uuid }) {
wildPokemon.effectedPokemon.entity?.killer = (battle.actors.firstOrNull { it.type == ActorType.PLAYER } as? PlayerBattleActor)?.entity
}
}
// broadcast victory / defeat
if (!wasCaught) {
val blackedOut = battle.isPvW && losers.any { it is PlayerBattleActor }
@@ -36,18 +36,10 @@ import java.util.function.Function
open class BattlePokemon(
val originalPokemon: Pokemon,
val effectedPokemon: Pokemon = originalPokemon,
var postBattlePokemonOperations: MutableList<(BattlePokemon) -> Unit> = mutableListOf(),
var postBattleEntityOperations: MutableList<(PokemonEntity) -> Unit> = mutableListOf()
val postBattleEntityOperation: (PokemonEntity) -> Unit = {}
) {
lateinit var actor: BattleActor
constructor(originalPokemon: Pokemon, effectedPokemon: Pokemon, postBattleEntityOperation: (PokemonEntity) -> Unit) : this(
originalPokemon = originalPokemon,
effectedPokemon = effectedPokemon,
postBattlePokemonOperations = mutableListOf<(BattlePokemon) -> Unit>(),
postBattleEntityOperations = mutableListOf(postBattleEntityOperation)
)
companion object {
fun safeCopyOf(pokemon: Pokemon): BattlePokemon {
//TOOD figure out a closer registry access (might have to break some method signatures for this (1.7?)
@@ -110,9 +102,6 @@ open class BattlePokemon(
/** A set of all the BattlePokemon that they faced during the battle (for exp purposes) */
val facedOpponents = mutableSetOf<BattlePokemon>()
/** The faint sequence number within the battle, or null if this pokemon has not fainted. */
var faintedAt: Int? = null
/**
* The [HeldItemManager] backing this [BattlePokemon].
*/
@@ -27,7 +27,6 @@ interface ShowdownService {
fun openConnection()
fun closeConnection()
fun startBattle(battle: PokemonBattle, messages: Array<String>)
fun endBattle(battle: PokemonBattle)
fun send(battleId: UUID, messages: Array<String>)
fun getRegistryData(type: String): JsonArray
fun sendRegistryData(data: Map<String, String>, type: String)
@@ -129,11 +129,6 @@ class GraalShowdownService : ShowdownService {
startBattleFunction.execute(this, battle.battleId.toString(), messages)
}
override fun endBattle(battle: PokemonBattle) {
val endBattleFunction = context.getBindings("js").getMember("endBattle")
endBattleFunction.execute(battle.battleId.toString())
}
override fun send(battleId: UUID, messages: Array<String>) {
sendToShowdown(battleId, messages)
}
@@ -62,11 +62,6 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
send(battle.battleId, messages)
}
override fun endBattle(battle: PokemonBattle) {
writer.write(">endbattle ${battle.battleId}\n")
acknowledge { Cobblemon.LOGGER.error("Failed to end battle ${battle.battleId}!") }
}
override fun send(battleId: UUID, messages: Array<String>) {
for (message in messages) {
writer.write("$battleId~$message\n")
@@ -133,10 +133,7 @@ class ApricornBlock(settings: Properties, val apricorn: Apricorn) : HorizontalDi
override fun isBonemealSuccess(world: Level, random: RandomSource, pos: BlockPos, state: BlockState) = true
override fun performBonemeal(world: ServerLevel, random: RandomSource, pos: BlockPos, state: BlockState) {
val curAge = state.getValue(AGE)
val newAge = curAge + 1
if (newAge > MAX_AGE) return
world.setBlock(pos, state.setValue(AGE, newAge), UPDATE_CLIENTS)
world.setBlock(pos, state.setValue(AGE, state.getValue(AGE) + 1), 2)
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
@@ -189,17 +186,17 @@ class ApricornBlock(settings: Properties, val apricorn: Apricorn) : HorizontalDi
* This uses [Block.dropResources] to handle the drops.
* It will also reset the [BlockState] of this block at the given location to the start of growth.
*
* @param world The [Level] the apricorn is in.
* @param world The [World] the apricorn is in.
* @param state The [BlockState] of the apricorn.
* @param pos The [BlockPos] of the apricorn.
* @return The [BlockState] after harvest.
*/
fun harvest(world: Level, state: BlockState, pos: BlockPos): BlockState {
// Uses loot tables, to change the drops use 'data/cobblemon/loot_tables/blocks/<color>_apricorn.json'
dropResources(state, world, pos)
Block.dropResources(state, world, pos)
// Don't use default as we want to keep the facing
val resetState = state.setValue(AGE, MIN_AGE)
world.setBlock(pos, resetState, UPDATE_CLIENTS)
world.setBlock(pos, resetState, Block.UPDATE_CLIENTS)
return resetState
}
@@ -81,32 +81,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
override fun isBonemealSuccess(world: Level, random: RandomSource, pos: BlockPos, state: BlockState) = !this.isMaxAge(state)
// Use Random Tick instead of BlockEntityTicker for performance optimization
override fun <T : BlockEntity> getTicker(world: Level, blockState: BlockState, blockWithEntityType: BlockEntityType<T>): BlockEntityTicker<T>? = null
// Enable Random Tick: only immature and non-rooted berries need to tick
override fun isRandomlyTicking(state: BlockState): Boolean {
return state.getValue(AGE) < FRUIT_AGE && !state.getValue(IS_ROOTED)
}
// Random Tick handler: uses time compensation to ensure correct growth speed
@Deprecated("Deprecated in Java")
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return
// processTick calculates elapsed time and updates timer, returns whether growth is needed
if (blockEntity.processTick(world, pos, state) && !world.getBlockTicks().hasScheduledTick(pos, this)) {
// Schedule growth for next tick to avoid tick scheduler conflicts during randomTick
world.scheduleTick(pos, this, 1)
}
}
// Scheduled tick handler: performs the actual growth
@Deprecated("Deprecated in Java")
override fun tick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
if (state.getValue(IS_ROOTED)) return
growHelper(world, random, pos, state)
}
override fun <T : BlockEntity> getTicker(world: Level, blockState: BlockState, blockWithEntityType: BlockEntityType<T>): BlockEntityTicker<T>? = createTickerHelper(blockWithEntityType, CobblemonBlockEntities.BERRY, BerryBlockEntity.TICKER)
init {
registerDefaultState(stateDefinition.any()
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import net.minecraft.world.item.Item
import net.minecraft.core.dispenser.DispenseItemBehavior
import net.minecraft.world.item.Items
import net.minecraft.world.item.alchemy.PotionContents
import net.minecraft.world.item.alchemy.Potions
import net.minecraft.world.level.block.DispenserBlock
object DispenserBehaviorRegistry {
private val behaviors = mutableMapOf<Item, DispenseItemBehavior>()
fun register(items: List<Item>, behaviorProvider: (Item) -> DispenseItemBehavior) {
for (item in items) {
behaviors[item] = behaviorProvider(item)
}
}
fun applyBehaviors() {
behaviors.forEach { (item, behavior) ->
DispenserBlock.registerBehavior(item, behavior)
}
}
// TODO: Seems like there can only 1 behavior per item, so registering the leaves with the honey bottle overrode the honey bottle behavior for the log.
// Registering a new behavior with `DispenserBlock.registerBehavior` will override any existing ones for that item, possibly even ones from Minecraft and other mods
// Will probably need to use an alternate way of implementing this to avoid conflicts.
fun registerDispenserBehaviors() {
// register(listOf(PotionContents.createItemStack(Items.POTION, Potions.WATER).item)) { SaccharineLogSlatheredBlock.createBehavior() }
// register(listOf(Items.HONEY_BOTTLE)) { SaccharineLogBlock.createBehavior() }
// register(listOf(Items.HONEY_BOTTLE, Items.GLASS_BOTTLE)) { item -> SaccharineLeafBlock.createBehavior(item)}
applyBehaviors()
}
}
@@ -19,7 +19,6 @@ import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.block.BaseEntityBlock
@@ -111,8 +110,6 @@ class DisplayCaseBlock(settings: Properties) : BaseEntityBlock(settings) {
override fun getRenderShape(state: BlockState) = RenderShape.MODEL
override fun getShadeBrightness(state: BlockState, level: BlockGetter, pos: BlockPos): Float = 0.75F
override fun getAnalogOutputSignal(state: BlockState, world: Level, pos: BlockPos): Int {
val stack = (world.getBlockEntity(pos) as DisplayCaseBlockEntity).getStack()
@@ -29,7 +29,6 @@ import net.minecraft.world.level.block.SoundType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.block.state.properties.IntegerProperty
@@ -44,6 +43,7 @@ class HeartyGrainsBlock(settings: Properties) : CropBlock(settings), SimpleWater
val CODEC = simpleCodec(::HeartyGrainsBlock)
const val MATURE_AGE = 6
const val AGE_AFTER_HARVEST = 3 // Last single block stage
val WATERLOGGED = BlockStateProperties.WATERLOGGED
val AGE: IntegerProperty = IntegerProperty.create("age", 0, MATURE_AGE)
val HALF: EnumProperty<DoubleBlockHalf> = BlockStateProperties.DOUBLE_BLOCK_HALF
@@ -21,7 +21,6 @@ import com.cobblemon.mod.common.util.isInBattle
import com.cobblemon.mod.common.util.playSoundServer
import com.cobblemon.mod.common.util.toVec3d
import com.cobblemon.mod.common.util.voxelShape
import com.cobblemon.mod.common.util.rotateShape
import com.mojang.serialization.MapCodec
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
@@ -72,10 +71,10 @@ class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWater
private val WEST_AABB_TOP = buildCollider(top = true, Direction.WEST)
private val EAST_AABB_TOP = buildCollider(top = true, Direction.EAST)
private val SOUTH_AABB_BOTTOM = buildCollider(top = false, Direction.SOUTH)
private val NORTH_AABB_BOTTOM = buildCollider(top = false, Direction.NORTH)
private val WEST_AABB_BOTTOM = buildCollider(top = false, Direction.WEST)
private val EAST_AABB_BOTTOM = buildCollider(top = false, Direction.EAST)
private val SOUTH_AABB_BOTTOM = rotateShape(Direction.EAST, Direction.SOUTH, EAST_AABB_BOTTOM)
private val NORTH_AABB_BOTTOM = rotateShape(Direction.EAST, Direction.NORTH, EAST_AABB_BOTTOM)
private val WEST_AABB_BOTTOM = rotateShape(Direction.EAST, Direction.WEST, EAST_AABB_BOTTOM)
private fun buildCollider(top: Boolean, direction: Direction): VoxelShape {
if (top) {

Some files were not shown because too many files have changed in this diff Show More