Compare commits

..
Author SHA1 Message Date
Test c346f84844 speed 2026-02-21 21:17:26 -05:00
Paul d1b8094539 Validate party positions of traded Pokémon upon trading 2026-02-16 11:23:24 +10:00
Paul b8d79af911 Migrate to a more unique tag name for data and config on scriptable entities, closes #1869 2026-02-16 10:57:11 +10:00
Hiroku a7198fd324 Merge branch 'fossil_crash' into 'main'
Adjust fossil creation

Closes #1801

See merge request cable-mc/cobblemon!2150
2026-02-08 01:16:45 +00:00
aeroeng15 bc69ce91f3 Changelog 2026-02-07 16:00:00 -07:00
aeroeng15 1de1d8cdc3 Adjust ordering of party modification 2026-02-07 15:26:36 -07:00
Hiroku 087bf75500 Merge branch 'party-selection-toast' into 'main'
Party Selection Tutorial Toasts

See merge request cable-mc/cobblemon!2148
2026-02-02 05:58:58 +00:00
Ceejay bac435ba7b Party Selection Tutorial Toasts 2026-02-02 05:58:58 +00:00
Hiroku 74a6106eb6 Merge branch 'snack-stack-fix' into 'main'
Fixes odd stacking behavior with the poke_bait item.

See merge request cable-mc/cobblemon!2143
2026-02-01 03:29:20 +00:00
Neovitalism 5ec993ad3c Update CHANGELOG.md 2026-01-31 21:13:10 -06:00
Paul 73a03d90da Resnapshot 2026-01-31 13:22:11 +10:00
Paul e6fda6137e Teeny tiny changelog [skip-ci] 2026-01-31 10:47:13 +10:00
Paul afae39acc8 Missed a bit of changelog [skip-ci] 2026-01-31 09:21:40 +10:00
Paul 37264aff0f Changelog stuff and no snapshot 2026-01-31 09:17:43 +10:00
Paul 2b60e6de77 Merge remote-tracking branch 'origin/lang-updates' 2026-01-31 09:12:27 +10:00
Hiroku 4f29e7457c Merge branch 'feature/riding-scrape' into 'main'
scrape riding data and fix script

See merge request cable-mc/cobblemon!2141
2026-01-30 09:43:44 +00:00
Polymeta 04a6ab31f4 rescrape data
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2026-01-30 09:26:22 +00:00
Hiroku a2cdc847dd Merge branch 'packet-sync-error-fix' into 'main'
Fixed packet sync issue with pokemon interactions, added "chance" requirement type

Closes #1933 and #1938

See merge request cable-mc/cobblemon!2147
2026-01-30 03:04:14 +00:00
阿鱼 0bca678f56 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-01-30 02:59:44 +00:00
Paul 067c3607aa Tweak /pctake to check the PC's box count and use that for constraints 2026-01-30 12:20:17 +10:00
Hiroku 823c1f6444 Merge branch 'main' into 'main'
Fixes PcTake not respecting defaultBoxCount

See merge request cable-mc/cobblemon!2146
2026-01-30 02:18:38 +00:00
Paul bfc00635cd Fixed packet sync issue with pokemon interactions, added "chance" requirement type 2026-01-30 12:16:01 +10:00
Hiroku b2e5b85ac5 Merge branch 'Custom-Ball-Resources-updated' into 'main'
updated ball texture locations missing from last update

See merge request cable-mc/cobblemon!2145
2026-01-30 00:24:49 +00:00
阿鱼 2c27476954 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.7% (9034 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-01-29 13:40:10 +00:00
Auristite aab78d84fc Fixes PcTake not respecting defaultBoxCount
Command is also missing lang option for "cobblemon.command.pctake.removed" (Removing Pokémon from self)
2026-01-29 04:46:25 +00:00
Zack the Ghast cb632c2a65 Translated using Weblate (Portuguese (Portugal))
Currently translated at 67.9% (6154 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-01-29 01:28:38 +00:00
Dragonwhisper92 8d219f1338 updated ball texture locations 2026-01-28 23:45:08 +00:00
Zack the Ghast 1e6a4ed984 Translated using Weblate (Portuguese (Portugal))
Currently translated at 67.7% (6143 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-01-28 21:10:25 +00:00
geumu 64240c31fc Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-01-28 17:35:35 +00:00
Zack the Ghast d2222c3858 Translated using Weblate (Portuguese (Portugal))
Currently translated at 67.6% (6129 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-01-28 14:44:02 +00:00
geumu c7f31c3e14 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-01-28 14:44:01 +00:00
Zack the Ghast 740e846b2d Translated using Weblate (Portuguese (Portugal))
Currently translated at 67.5% (6125 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-01-28 08:26:35 +00:00
Neovitalism 246d00aa3f Fixes odd stacking behavior with the poke_bait item. 2026-01-27 21:45:05 -06:00
Zack the Ghast 06f9d60595 Translated using Weblate (Portuguese (Portugal))
Currently translated at 67.5% (6123 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-01-27 04:12:54 +00:00
Zack the Ghast d54439ce14 Translated using Weblate (Portuguese (Portugal))
Currently translated at 67.3% (6103 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-01-26 02:31:37 +00:00
Teggy 32ee4bb72a Translated using Weblate (Spanish)
Currently translated at 84.3% (7644 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-01-25 13:02:37 +00:00
Polymeta e7d2a46cc0 Bumping snapshot version 2026-01-25 06:57:31 +00:00
Yasito 3ee94ec076 Translated using Weblate (French)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-25 03:06:53 +00:00
Yasito 589293abc4 Translated using Weblate (French (Canada))
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-25 03:06:49 +00:00
Paul 279865cc7c Resnaps your shot 2026-01-25 11:53:29 +10:00
Paul b597b149c3 Snapnot 2026-01-25 10:18:32 +10:00
Paul b7f592f2a8 Relocate mongodb packages 2026-01-25 10:18:02 +10:00
Paul 70e17c22e7 Merge remote-tracking branch 'origin/lang-updates' 2026-01-25 10:17:49 +10:00
Yasito 51b18ca0f6 Translated using Weblate (French)
Currently translated at 99.6% (9027 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-25 00:16:58 +00:00
Yasito a83f243a3b Translated using Weblate (French (Canada))
Currently translated at 99.9% (9059 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-25 00:16:55 +00:00
Weblate f5b088c708 Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/
2026-01-25 00:14:04 +00:00
Yasito dc454cbb68 Translated using Weblate (French)
Currently translated at 99.5% (9022 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-25 00:13:56 +00:00
Yasito 3b99e38da2 Translated using Weblate (French (Canada))
Currently translated at 99.9% (9057 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-25 00:13:54 +00:00
Paul 483af57964 Merge remote-tracking branch 'origin/lang-updates' 2026-01-25 10:12:48 +10:00
Dmytro Bunnua a941bdddf3 Translated using Weblate (Ukrainian)
Currently translated at 76.9% (6971 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/uk/
2026-01-24 18:24:12 +00:00
Teggy 246ba4a93b Translated using Weblate (Spanish)
Currently translated at 83.9% (7611 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-01-24 18:24:09 +00:00
Paul 3347c084ed More changelog [skip-ci] 2026-01-24 22:42:58 +10:00
Paul 8175cee454 More translations 2026-01-24 22:11:15 +10:00
Paul 37d54053a5 Merge remote-tracking branch 'origin/lang-updates' 2026-01-24 22:10:10 +10:00
Dmytro Bunnua b8846bd74c Translated using Weblate (Ukrainian)
Currently translated at 76.8% (6966 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/uk/
2026-01-24 11:47:21 +00:00
Paul 1716e135c4 Changelog [skip-ci] 2026-01-24 21:45:14 +10:00
Paul 0ac804cfcb Cleanup 2026-01-24 21:20:50 +10:00
Hiroku aecc132814 Merge branch 'pokeballUIResourcePathChange' into 'main'
ball_icon resource location changes

See merge request cable-mc/cobblemon!2113
2026-01-24 11:13:26 +00:00
Hiroku 8b47876dff Merge branch 'Add-Plaques-to-Village-Pokecenters' into 'main'
Adding Plaques to Village Pokecenters

See merge request cable-mc/cobblemon!2139
2026-01-24 09:27:56 +00:00
Slippy ffc108953a Adding Plaques to Village Pokecenters 2026-01-24 01:51:33 -06:00
Paul 0a106174fe Changelog cleanup [skip-ci] 2026-01-24 15:59:27 +10:00
Paul 90210bee3c Fixed cottonee cries being inconsistent due to not having appropriate pose type coverage 2026-01-24 15:13:08 +10:00
Paul 8603cd4ad0 Merge remote-tracking branch 'origin/main' into Expression-stuffs 2026-01-24 13:56:14 +10:00
Hiroku 7b2c6827c2 Merge branch 'Expression-stuffs' into 'main'
Expression stuffs

See merge request cable-mc/cobblemon!2138
2026-01-24 03:55:02 +00:00
Paul 902b4a6d21 Fixed croagunk and toxicroak playing cry animations without the sound 2026-01-24 13:54:41 +10:00
Hiroku a847cb5926 Merge branch 'fix-plain-aprijuice-prefix' into 'main'
Fix Aprijuice 'Plain' prefix

See merge request cable-mc/cobblemon!2137
2026-01-24 03:46:05 +00:00
Paul 050c6f5adc Merge remote-tracking branch 'origin/Expression-stuffs' into Expression-stuffs 2026-01-24 13:41:23 +10:00
Paul fb95fb3cf7 Various cry corrections from implementation 2026-01-24 13:41:11 +10:00
Carmendar d507367411 Bird stamina changes. 2026-01-23 21:30:43 -06:00
Paul faa19cebcb Fixed perma zero stamina on horses when landing from bird 2026-01-24 13:16:38 +10:00
Paul aced374367 Fixed birds falling out of the sky and not gliding all chill like 2026-01-24 12:40:04 +10:00
Paul d424a6f1d3 Fixed stamina stat flowing to crazy negative from bird sometimes 2026-01-24 11:58:25 +10:00
Carmendar 71bb1c32de stamina expression changes for Bird and Hover. Changes to Mantine riding. 2026-01-23 18:56:17 -06:00
Carmendar f726fcedb9 Merge branch 'main' into implement_pokemon 2026-01-23 18:09:48 -06:00
Weblate 77344ccc2f Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/
2026-01-23 17:29:44 +00:00
Dmytro Bunnua 90bc16be90 Translated using Weblate (Ukrainian)
Currently translated at 76.8% (6960 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/uk/
2026-01-23 17:29:37 +00:00
Gustavo Puerari d1b743a01f Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.3% (8908 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-01-23 17:29:33 +00:00
Teggy aed651c0a0 Translated using Weblate (Spanish)
Currently translated at 83.9% (7608 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-01-23 17:29:28 +00:00
Faintful 4c477e1675 Add changelog 2026-01-23 17:36:05 +01:00
Faintful d1cdc6789c Handle case for LOW quality Aprijuice in getName() for proper 'Plain' prefix 2026-01-23 17:33:04 +01:00
geumu cd3127b983 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-01-23 13:22:11 +00:00
Watuneni iteite 68f5eff048 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-01-23 13:22:06 +00:00
Paul c3d2918a2b Fixed a crash when joining a server and a player is riding nearby 2026-01-23 17:49:57 +10:00
Paul 0432525c06 Throh resize 2026-01-23 17:04:45 +10:00
Paul a60f27e282 Fixed implemented flag missing from the new 1.7.2 pokemon, subtle size changes 2026-01-23 17:04:14 +10:00
Test 5f0182cb7e fix type asset 2026-01-23 01:48:49 -05:00
Paul 4a3ae9407b Translation changelog [skip-ci] 2026-01-23 16:44:32 +10:00
Paul 766c2838d2 Merge remote-tracking branch 'origin/lang-updates' 2026-01-23 14:34:19 +10:00
Hiroku 4cb95589b4 Merge branch 'more-fixes' into 'main'
More fixes

See merge request cable-mc/cobblemon!2134
2026-01-23 04:30:49 +00:00
Hiroku a8d3c2dd52 Merge branch '1.7.2-spawns' into 'main'
Added spawns. Fixed spawns. Updated tags.

Closes #1896

See merge request cable-mc/cobblemon!2131
2026-01-23 04:13:07 +00:00
Test cb5d7b6ad7 rm unused 2026-01-22 23:05:38 -05:00
Test c7dcc64595 sync repo assets 2026-01-22 23:00:10 -05:00
Paul 6573e08da7 Fix for packet handling to ensure all packets are handled on main and without extra delays on Fabric, closes #1903 2026-01-23 13:37:36 +10:00
Paul cd695ade4a Apparently I put more changelog in than was meant to be there 2026-01-23 13:22:37 +10:00
Paul 55cb413cfc Merge remote-tracking branch 'origin/main' into 1.7.2-spawns 2026-01-23 13:11:50 +10:00
Paul 4f1bf7fcbb Changelog for spawns [skip-ci] 2026-01-23 13:11:42 +10:00
Test 154ee80ead fix some block issues 2026-01-22 21:32:51 -05:00
Test 1c9f9bb198 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2026-01-22 20:38:08 -05:00
Test 6836343f11 ride summary 2026-01-22 20:37:46 -05:00
RedGenesectNinja aa0d1cd943 Updated changelog 2026-01-22 14:44:46 -06:00
Hiroku 798f1da8b3 Merge branch 'main' into 'main'
Issue 1926: Make SpawnBaitInfluence apply all effects correctly

See merge request cable-mc/cobblemon!2130
2026-01-22 13:44:44 +00:00
Andy d98efb52b6 Add changelog line and extend author tag 2026-01-22 08:38:13 -05:00
Kenji_64 2f27a03f08 Alolan Raichu can look around in the menu now (yay) 2026-01-22 13:36:19 +01:00
Kenji_64 e33025b1fa Fixed the weird eye clipping on Dragapult (fr this time) 2026-01-22 13:36:00 +01:00
Kenji_64 ade2481f42 Treecko line has their cries back 2026-01-22 13:35:39 +01:00
Hiroku 576e2301ce Merge branch 'open-actor-classes' into 'main'
Mark the actor classes as open so they can be extended.

See merge request cable-mc/cobblemon!2129
2026-01-22 12:19:06 +00:00
Polymeta a568d45d75 [skip-ci] tidy up changelog take two 2026-01-22 09:58:38 +00:00
Hiroku bc19a7e4c1 Merge branch 'decor-split' into 'main'
Decor split

See merge request cable-mc/cobblemon!2127
2026-01-22 09:42:35 +00:00
Polymeta 616e438f17 [skip-ci] tidy up changelog 2026-01-22 09:40:47 +00:00
Polymeta 9bb11c46d5 Merge branch 'implement_pokemon' into 'main'
Implement pokemon

Closes #1921 and #1800

See merge request cable-mc/cobblemon!2063
2026-01-22 09:28:25 +00:00
Carmendar 5f470bb703 Honchkrow and Mantine camera fixes. 2026-01-21 23:25:53 -06:00
Andy 276f13cea5 1926: Re-add affectWeight comment 2026-01-22 00:08:34 -05:00
Andy ac069687f1 1926: Changed SpawnBaitInfluence to apply all bait effects properly in affectWeight 2026-01-22 00:07:14 -05:00
Deltric f248c22eed Fix initialPos being able to change and changelog 2026-01-21 22:54:53 -06:00
RedGenesectNinja 65a5687f92 Fixed Dusknoir's stomach mouth lips glowing while it sleeps 2026-01-21 22:27:11 -06:00
Deltric ea50fa534b Mark the actor classes as open so they can be extended. 2026-01-21 21:35:03 -06:00
RedGenesectNinja 4bd3c4af58 Updated changelog 2026-01-21 21:20:16 -06:00
RedGenesectNinja 283d80f7ed Implemented Croagunk and Toxicroak's animations 2026-01-21 21:19:22 -06:00
Veraxiel 0238ca80f0 Added spawns. Fixed spawns. Updated tags. 2026-01-21 18:53:40 -05:00
RedGenesectNinja d24c5fe874 Fixed a mistake I made with file placement 2026-01-21 15:32:14 -06:00
RedGenesectNinja e65e21f2ff Fixed Chimecho's cry not playing a sound 2026-01-21 15:21:02 -06:00
Carmendar e1d417718f Added Flygon jump and Mantine ride anims with temp ride stats. 2026-01-21 02:25:05 -06:00
Polymeta d4308b0a4f Merge branch 'fix-battle-memory-leak' into 'main'
Fixed memory leak from battles not being cleaned up after ending.

See merge request cable-mc/cobblemon!2075
2026-01-21 08:09:44 +00:00
Test bc0d530484 loisence 2026-01-20 19:19:53 -05:00
Jerzykv 56650418d2 Implemented Throh and Sawk 2026-01-20 20:32:21 +01:00
Jerzykv 0543b84d34 The battle idle should probably play the battle idle animation 2026-01-20 19:57:45 +01:00
Jerzykv 1f50687a59 Re-added Honchkrow's driving license 2026-01-20 19:53:25 +01:00
Polymeta ed04faf0d8 Merge branch 'dispenser-fix' into 'main'
Resolved Dispenser Behaviors not working

See merge request cable-mc/cobblemon!2118
2026-01-20 14:46:55 +00:00
Aram 1ed020f3e0 Resolved Dispenser Behaviors not working 2026-01-20 14:46:54 +00:00
Polymeta 7e385d8c94 Merge branch 'default-offest' into 'main'
[FEAT] Add `default_seat` option to seat offset posers

See merge request cable-mc/cobblemon!1999
2026-01-20 14:46:44 +00:00
Polymeta ee509b5438 Merge branch 'molang-inventory-and-move-utility' into 'main'
molang additions: Move struct accessor and player inventory utils

See merge request cable-mc/cobblemon!2103
2026-01-20 14:46:34 +00:00
Jerzykv ac9394131c Implemented Litleo and Pyroar - Changelog 2026-01-20 12:01:09 +01:00
Jerzykv d058a306a7 Implemented Litleo and Pyroar 2026-01-20 11:58:48 +01:00
Jerzykv b9be0c3fcb Swirlix and Slurpuff cry fixes 2026-01-20 10:14:16 +01:00
Jerzykv b59b46568a Swirlix and Slurpuff poser changes 2026-01-20 10:14:11 +01:00
Jerzykv 408cbc8c49 Slurpuff and Aromatisse scale changes 2026-01-20 10:13:55 +01:00
Test 1537816132 log of change 2026-01-20 00:56:36 -05:00
Test 1705639950 loot 2026-01-20 00:50:04 -05:00
Test ce32541dd6 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into decor-split 2026-01-19 23:45:28 -05:00
Test 3ffea4f4dd split items 2026-01-19 23:44:20 -05:00
Hiroku f942d7c34a Merge branch 'misc-additions-fixes' into 'main'
Couple of misc API additions and bug fixes.

See merge request cable-mc/cobblemon!2125
2026-01-19 02:16:09 +00:00
Deltric 0f1ada4624 Pass in pnx to the event 2026-01-18 18:52:27 -06:00
Deltric b4ee4629bf Couple of misc API additions and bug fixes. 2026-01-18 17:57:28 -06:00
Paul d0b64e2d82 Respect the BYPASSES_INVULNERABILITY damage tag 2026-01-18 22:12:25 +10:00
Jerzykv a8ce3c2175 Fixed Wishiwashi's School Form, Fixes #1921 2026-01-18 12:39:16 +01:00
Jerzykv 80ae127379 Implemented Spritzee and Aromatisse. Smells good. 2026-01-18 12:36:48 +01:00
Jerzykv bd3a9fb3af Implemented Swirlix and Slurpuff. How sweet! 2026-01-18 11:28:15 +01:00
Instrafe d0eaccb81b Fixed Ferroseed and Ferrothorn's posers not identifying a root bone (woops) 2026-01-17 12:12:08 -05:00
Paul 1ed2042283 Fixed /calculateseatpositions expecting no underscore when actually we always use an underscore 2026-01-17 22:32:57 +10:00
Deltric 0b531d967e Merge remote-tracking branch 'origin/fix-battle-memory-leak' into fix-battle-memory-leak
# Conflicts:
#	common/src/main/resources/data/cobblemon/showdown.zip
2026-01-17 03:42:38 -06:00
Deltric b0d1aec9ab Update showdown 2026-01-17 03:42:21 -06:00
Deltric f4d47098b5 Fixed memory leak from battles not being cleaned up after ending. 2026-01-17 03:42:08 -06:00
Instrafe 1989b8aa92 Implemented remodels for Ferroseed and Ferrothorn 2026-01-16 17:06:45 -05:00
Hiroku 948ca61ef3 Merge branch 'fix-super-potion-ingredients-tag' into 'main'
Fix super potion ingredients tag

See merge request cable-mc/cobblemon!2121
2026-01-16 08:27:19 +00:00
Hiroku e60aca30ba Merge branch 'patch-2' into 'main'
Fix Syrupy Apple missing from evolution items tag

See merge request cable-mc/cobblemon!2120
2026-01-16 08:26:22 +00:00
Hiroku fb5055c39e Merge branch 'form_crash' into 'main'
Initialize FormData when updating

Closes #1916

See merge request cable-mc/cobblemon!2122
2026-01-16 08:20:23 +00:00
Paul dfb5650121 Merge remote-tracking branch 'origin/main' 2026-01-16 18:17:01 +10:00
Paul 8a0cbf28fe Fixed battles not ending fully when a switch is in progress, closes #1917 2026-01-16 18:16:11 +10:00
aeroeng15 a6b9060d57 Changelog 2026-01-15 20:54:54 -07:00
aeroeng15 8e57995e44 Make It Proper 2026-01-15 20:51:59 -07:00
aeroeng15 1d8257808c Initialize rather than set; seems to fix the issue 2026-01-15 20:42:14 -07:00
Carmendar e290fe9c75 Modified Hover expressions and buffs/nerfs for hover mounts. 2026-01-15 21:23:34 -06:00
Jerzykv 06a50cfeeb Changelog for the cottons 2026-01-15 11:12:17 +01:00
Jerzykv 00888c8ad5 Implemented Cottonee and Whimsicott remodels 2026-01-15 11:11:44 +01:00
Faintful e3582ccfb4 Add changelog 2026-01-14 19:49:11 +01:00
Faintful 4c6822b1c6 Merge remote-tracking branch 'upstream/main' into fix-super-potion-ingredients-tag 2026-01-14 19:46:54 +01:00
Faintful 2e6a4c7341 Change Hondew for Aguav 2026-01-14 19:28:49 +01:00
Micky 8edb5e1013 Fix Syrupy Apple missing from evolution items tag 2026-01-14 18:25:06 +00:00
Polymeta 6fb139cbb9 Merge branch 'pokemon-interactions-fixes' into 'main'
Pokémon Interaction fixes

See merge request cable-mc/cobblemon!2117
2026-01-14 00:03:33 +00:00
lion c81c95142b Pokémon Interaction fixes 2026-01-14 00:03:32 +00:00
Hiroku afde822860 Edit CHANGELOG.md [skip-ci] 2026-01-12 10:50:47 +00:00
Hiroku 474c386535 Merge branch 'main' into 'main'
Fix Fresh Start Mochi EV Reset

See merge request cable-mc/cobblemon!2115
2026-01-12 10:48:40 +00:00
RedGenesectNinja 3963e83717 Implemented Ducklett and Swanna's cries with placeholder animations 2026-01-12 01:04:46 -06:00
Konoha 7893e365da yolo: drop item on give_item if inventory is full & sneak in a fix for active_dialogue 2026-01-11 18:50:52 -05:00
ToothCollector 71b9ae8dee add fix to CHANGELOG.md 2026-01-11 21:31:22 +02:00
ToothCollector b87b47d62a Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon 2026-01-11 21:28:04 +02:00
Hiroku 2bb85718d7 Merge branch 'main' into 'main'
Fix Adorn compatibility

See merge request cable-mc/cobblemon!2112
2026-01-11 12:21:25 +00:00
Tate Frost ee187d7b89 Delete file + update Adorn resource pack metadata
- Delete config file that was committed in error
- Update Adorn resource pack metadata to reflect new wood type
2026-01-10 22:30:27 -06:00
Hiroku b6a7051b2c Fixed galarian weezing blink crash, closes #1800 2026-01-11 04:28:37 +00:00
Tate Frost 3532cac278 Update CHANGELOG.md 2026-01-10 22:18:01 -06:00
Hiroku 1447ab25b4 Merge branch 'CombeeWorldGenFix' into 'main'
CombeeWorldGenFix

See merge request cable-mc/cobblemon!2071
2026-01-11 02:55:56 +00:00
Hiroku 9a06ca78c6 Merge branch 'fix-mongo-driver' into 'main'
Fix MongoDB ClassNotFoundException by including drivers at runtime

See merge request cable-mc/cobblemon!2098
2026-01-11 02:47:10 +00:00
Hiroku f6ba70634b Merge branch 'double-battle-gimmicks' into 'main'
Fix double battle gimmicks not being processed

See merge request cable-mc/cobblemon!2094
2026-01-11 02:46:36 +00:00
Hiroku 148fd04a93 Merge branch 'molang-evaluate_expression' into 'main'
molang addition: exception handling for run_molang

See merge request cable-mc/cobblemon!2102
2026-01-11 02:12:07 +00:00
Hiroku 17f60623ee Merge branch 'effect-id-regex-update' into 'main'
Custom messages for datapack moves and abilities

See merge request cable-mc/cobblemon!2106
2026-01-11 02:08:42 +00:00
Hiroku c5ece27c11 Merge branch '1861-galarien_mrmime_mount' into 'main'
Fix Galarian Mr. Mime incorrectly being rideable.

Closes #1861

See merge request cable-mc/cobblemon!2107
2026-01-11 02:02:14 +00:00
Hiroku 296ccd1a76 Merge branch 'main' into 'main'
Fix pasture block incorrect hit-box when facing north and south.

See merge request cable-mc/cobblemon!2109
2026-01-11 02:01:44 +00:00
ToothCollector 82a4f71f24 fix(FreshStartMochiItem.kt): Set all Pokemon's EVs to zero with the appropriate method. 2026-01-10 17:10:15 +02:00
Jerzykv 2cb1cf2f83 tiny fix on Togekiss 2026-01-10 13:36:40 +01:00
阿鱼 f13a4e0e24 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-01-08 18:45:37 +00:00
Dragonwhisper92 17e1bbd6a1 oops changelog extra '-' removed 2026-01-07 20:00:26 +00:00
Dragonwhisper92 c36ff0a0fe ball_icon resource location changes
Changed the resource location of pokeball icons in the gui to use the balls namespace instead of cobblemon, allowing mods to properly use their own name space for these textures
2026-01-07 19:57:36 +00:00
Tate Frost 08b58e2f78 Fix Adorn compatibility
- Fixed Apricorn block model rotation for counters/sinks/cupboards/drawers to match that of most recent version of Adorn
- Added Saccharine wood + Adorn compatibility
2026-01-07 02:04:52 -06:00
Merv 62d2b8db2d Edit CHANGELOG.md 2026-01-06 18:47:45 +00:00
Merv 3869f7ed93 Merge branch cobblemon:main into main 2026-01-05 23:09:08 +00:00
Jerzykv 8dbb350230 minor fix to apricorn textures 2026-01-05 21:56:02 +01:00
Dragonwhisper92 c9c44872d6 Updated Changelog. 2026-01-05 19:35:05 +00:00
Dragonwhisper92 cae53efedc Updated ActivateInstruction.kt to have an optional message parameter. 2026-01-05 19:14:40 +00:00
Jerzykv 52f9ffb1f6 fixed Politoed's drop again. thanks scraper 2026-01-05 12:23:07 +01:00
Polymeta 5fac24cee8 Merge branch 'Molang-SimpleDateFormat-Fix' into 'main'
Fixed Molang functions:

See merge request cable-mc/cobblemon!2105
2026-01-05 11:22:45 +00:00
Polymeta 1954dfec80 Merge branch '1784-riding_stats_order' into 'main'
Fix riding stat boosts to always render in the same order

Closes #1784

See merge request cable-mc/cobblemon!2108
2026-01-05 11:20:29 +00:00
Landon 2eea2b64c2 Merge branch 'bag-clause' into 'main'
Bag Clause (Preventing Item use in Battles)

See merge request cable-mc/cobblemon!1849
2026-01-05 08:12:36 +00:00
GDWR a127a93be8 Sort boosts when rendering to remove the jumping of stats between items
The sort uses the key. As `RidingStat` it sorts them by the enum value.
2026-01-04 20:27:42 +00:00
GDWR 9b32f85817 Set an empty riding definition for Galarian Mr. Mime to avoid inheriting the default definition 2026-01-04 17:28:02 +00:00
Dragonwhisper92 ec139d2677 Updated Effect.kt to use a custom REGEX entry 2026-01-04 16:46:44 +00:00
Landon Wills 4327be0cf9 Omit bag clause from getting sent to showdown 2026-01-04 02:22:32 -05:00
Landon Wills c25c832b31 Remove import 2026-01-04 01:21:20 -05:00
Landon Wills eabaabc535 Move bag clause check to bag items instead of pokemon entity 2026-01-04 01:19:26 -05:00
Dragonwhisper92 9acf97f5a0 Updated CHANGELOG.md 2026-01-04 00:18:24 +00:00
Dragonwhisper92 24fc212c76 Updated CHANGELOG.md 2026-01-04 00:15:32 +00:00
Hiroku 04f88bdd63 Merge branch 'form-change-move-sanitization-fix' into 'main'
Fix the improper sanitization of moves on mons with compounding properties

Closes #1853 and #1846

See merge request cable-mc/cobblemon!2085
2026-01-04 00:05:26 +00:00
Dragonwhisper92 a4eb58aa57 Fixed molang functions:
- date_local_time
- date_of
- date_is_after
too use the correct SimpleDateFormat of "dd/MM/yyyy"
2026-01-03 23:40:12 +00:00
Lucas 030195e3ff Translated using Weblate (French)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-03 08:52:44 +00:00
Yasito d21a52ae68 Translated using Weblate (French)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-03 08:52:43 +00:00
Yasito 3c1f1dbacb Translated using Weblate (French (Canada))
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-03 08:52:42 +00:00
Merv 6704d4e5ee Maybe fix pasture block incorrect hitbox 2026-01-03 02:05:03 +00:00
Lucas 787c4851ff Translated using Weblate (French)
Currently translated at 99.9% (9021 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:02:21 +00:00
Yasito bf6e7fafd3 Translated using Weblate (French)
Currently translated at 99.9% (9021 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:02:20 +00:00
Lucas ea6df764c0 Translated using Weblate (French)
Currently translated at 99.9% (9020 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:01:41 +00:00
Yasito f242de272d Translated using Weblate (French)
Currently translated at 99.9% (9020 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:01:41 +00:00
Lucas 5232e2e9bc Translated using Weblate (French)
Currently translated at 99.9% (9019 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:01:09 +00:00
Yasito ca35898243 Translated using Weblate (French)
Currently translated at 99.9% (9019 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:01:08 +00:00
Lucas 869457d235 Translated using Weblate (French)
Currently translated at 99.9% (9018 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:00:52 +00:00
Yasito 6736c8160b Translated using Weblate (French)
Currently translated at 99.9% (9018 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:00:51 +00:00
Lucas 243c50550d Translated using Weblate (French)
Currently translated at 99.9% (9017 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:00:37 +00:00
Yasito fe7d3ef23a Translated using Weblate (French)
Currently translated at 99.9% (9017 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:00:36 +00:00
Lucas 57ad77fc39 Translated using Weblate (French)
Currently translated at 99.9% (9016 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 21:00:10 +00:00
Lucas d70e7bd1b3 Translated using Weblate (French)
Currently translated at 99.9% (9015 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:59:34 +00:00
Yasito 254cc931ea Translated using Weblate (French)
Currently translated at 99.9% (9015 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:59:34 +00:00
Lucas 01fe5cffe8 Translated using Weblate (French)
Currently translated at 99.9% (9014 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:59:19 +00:00
Yasito 3e18995a37 Translated using Weblate (French)
Currently translated at 99.9% (9014 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:59:18 +00:00
Yasito ff161c9c9b Translated using Weblate (French)
Currently translated at 99.9% (9013 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:58:36 +00:00
Lucas 6b7b4f326d Translated using Weblate (French)
Currently translated at 99.9% (9013 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:58:35 +00:00
Lucas f50f7dec29 Translated using Weblate (French)
Currently translated at 99.8% (9012 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:58:17 +00:00
Yasito a5def20c58 Translated using Weblate (French)
Currently translated at 99.8% (9012 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:58:16 +00:00
Yasito b23204f9c9 Translated using Weblate (French)
Currently translated at 99.8% (9011 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:57:51 +00:00
Lucas 4972de0aaa Translated using Weblate (French)
Currently translated at 99.8% (9011 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:57:50 +00:00
Lucas 58a1f3d7b4 Translated using Weblate (French)
Currently translated at 99.8% (9010 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:57:33 +00:00
Yasito f516edb858 Translated using Weblate (French)
Currently translated at 99.8% (9010 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:57:32 +00:00
Lucas 161aa952fa Translated using Weblate (French)
Currently translated at 99.8% (9008 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:55:43 +00:00
Yasito 3b26a13ad6 Translated using Weblate (French)
Currently translated at 99.8% (9008 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:55:43 +00:00
Lucas 014189217a Translated using Weblate (French)
Currently translated at 99.8% (9007 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:55:29 +00:00
Yasito 978debb40c Translated using Weblate (French)
Currently translated at 99.8% (9007 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:55:28 +00:00
Lucas 5be707811e Translated using Weblate (French)
Currently translated at 99.8% (9006 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:55:13 +00:00
Yasito ac44a98f8a Translated using Weblate (French)
Currently translated at 99.8% (9006 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:55:12 +00:00
Lucas 03ecc2ae8d Translated using Weblate (French)
Currently translated at 99.8% (9005 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:54:13 +00:00
Yasito 1518379107 Translated using Weblate (French)
Currently translated at 99.8% (9005 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:54:12 +00:00
Yasito a58c8c59e1 Translated using Weblate (French)
Currently translated at 99.8% (9004 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:53:58 +00:00
Lucas 37959b5048 Translated using Weblate (French)
Currently translated at 99.8% (9004 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:53:58 +00:00
Yasito cbcc9fc6f1 Translated using Weblate (French (Canada))
Currently translated at 99.7% (9002 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-02 20:53:57 +00:00
Yasito d236aaa7da Translated using Weblate (French)
Currently translated at 99.7% (9000 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:50:35 +00:00
Lucas a2cd5a671c Translated using Weblate (French)
Currently translated at 99.7% (9000 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:50:35 +00:00
Lucas 1d6a45bf4d Translated using Weblate (French)
Currently translated at 99.7% (8998 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:49:59 +00:00
Yasito 5bfe703ed7 Translated using Weblate (French)
Currently translated at 99.7% (8998 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:49:58 +00:00
Yasito fc8485388e Translated using Weblate (French)
Currently translated at 99.7% (8997 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:45:38 +00:00
Lucas a5593b3131 Translated using Weblate (French)
Currently translated at 99.7% (8997 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:45:38 +00:00
Yasito 9541bf3267 Translated using Weblate (French (Canada))
Currently translated at 99.6% (8991 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-02 20:45:37 +00:00
Lucas 1037fe0a0e Translated using Weblate (French)
Currently translated at 99.6% (8989 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:38:19 +00:00
Yasito a6eea3198a Translated using Weblate (French)
Currently translated at 99.6% (8989 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:38:19 +00:00
Yasito b28e2313a8 Translated using Weblate (French (Canada))
Currently translated at 99.6% (8988 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-02 20:38:19 +00:00
Lucas 0f0b4e6c86 Translated using Weblate (French)
Currently translated at 99.6% (8988 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:37:45 +00:00
Yasito e033467054 Translated using Weblate (French)
Currently translated at 99.6% (8988 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:37:45 +00:00
Yasito 0f092bf6bf Translated using Weblate (French (Canada))
Currently translated at 99.6% (8987 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-02 20:37:44 +00:00
Lucas 66ba762360 Translated using Weblate (French)
Currently translated at 99.6% (8987 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:37:01 +00:00
Yasito c7c11838a0 Translated using Weblate (French)
Currently translated at 99.6% (8987 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2026-01-02 20:37:01 +00:00
Yasito 301d80fabe Translated using Weblate (French (Canada))
Currently translated at 99.6% (8986 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2026-01-02 20:37:00 +00:00
Hiroku c88087de29 Merge branch 'main' into 'main'
Small improvements to the Battle AI

See merge request cable-mc/cobblemon!2101
2026-01-02 00:38:26 +00:00
Konoha fade5502d9 molang additions: Move struct accessor and player inventory utils 2026-01-01 15:31:40 -05:00
Konoha 86bb802140 adjustment: exception handling to run_molang 2026-01-01 11:44:29 -05:00
GGavino1 6b644b384d Updated CHANGELOG.md to include AI changes 2026-01-01 15:00:15 +00:00
Konoha c370af8914 feature: molang function for safe evaluation of booleans 2025-12-31 22:23:50 -05:00
GGavino1 1cd6d2bfc7 Edit StrongBattleAI.kt 2025-12-31 23:15:52 +00:00
Test fc720916fb wall block properties 2025-12-31 00:24:39 -05:00
Jerzykv ce55035408 changelog 2025-12-30 14:46:38 +01:00
Jerzykv d4665ddaeb implemented Falinks remodel 2025-12-30 14:44:46 +01:00
Jerzykv 4375c6f667 fixed Revavroom's hitbox. Who implemented this guy (it was me) 2025-12-30 14:43:24 +01:00
Konoha 1edeae2a60 fix: let's actually fix 2025-12-27 09:48:49 -05:00
mkh 409f1056b9 fix: Add MongoDB driver dependency to Fabric/NeoForge build configuration and shade it into the mod jar to resolve ClassNotFoundException. 2025-12-26 17:31:46 +08:00
Landon Wills d8c470db3d Oops, forgot a file 2025-12-23 01:28:50 -05:00
Landon Wills c642c4b84b Update changelog 2025-12-23 01:22:01 -05:00
Landon Wills 0b80f7e547 Make the gimmick buttons work with the back button 2025-12-23 01:18:35 -05:00
Landon Wills d543f45607 Fix double battle gimmicks not being processed, prevent people from trying to use the same gimmick multiple times on the same turn 2025-12-23 00:43:31 -05:00
Test e5699c1cdc plaques, policies 2025-12-22 01:34:10 -05:00
RedGenesectNinja f4a7c6e873 Implemented the remodels for Chingling and Chimecho 2025-12-21 22:40:17 -06:00
Konoha 2b4fdfd219 changelog: sanitization fix 2025-12-21 15:40:17 -05:00
geumu 3bef1dad4a Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-20 19:34:20 +00:00
geumu da50ee59cf Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-20 14:40:56 +00:00
Hiroku 1a3b655d3f Merge branch 'the-tiniest-of-tiny-changes' into 'main'
Edit pokemon_model.json

See merge request cable-mc/cobblemon!2091
2025-12-20 12:41:36 +00:00
dhi_holo 1f5f278970 Edit pokemon_model.json 2025-12-20 21:25:12 +10:00
Hiroku 0b4eb5239a Merge branch 'in-flight-dismounting-config' into 'main'
Add enable in-flight dismounting config

See merge request cable-mc/cobblemon!2079
2025-12-20 06:01:12 +00:00
lion 118e8f6205 Add enable in-flight dismounting config 2025-12-20 06:01:12 +00:00
Hiroku cf126c5906 Merge branch 'molang-is-love-molang-is-life' into 'main'
Fixed the `run_script` Molang function to not fail if the environment's context is null.

See merge request cable-mc/cobblemon!2090
2025-12-20 01:59:22 +00:00
Spicy 645cf61911 Fixed the run_script Molang function to not fail if the environment's context is null. 2025-12-19 19:48:27 -06:00
arvid6 6e8985d97e Translated using Weblate (Spanish)
Currently translated at 84.2% (7599 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-12-19 08:15:16 +00:00
geumu 19c4c0d50d Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-19 08:15:15 +00:00
阿鱼 b23110950e Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-12-19 08:15:14 +00:00
Watuneni iteite 60c213c44b Translated using Weblate (Japanese)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-12-19 08:15:13 +00:00
Hiroku 87d5ede3dd Merge branch 'RestoreCombeeLeavesPathing' into 'main'
RestoreCombeeLeavesPathing

See merge request cable-mc/cobblemon!2046
2025-12-19 07:36:50 +00:00
Hiroku 203e5d89cd Merge branch 'label-consistency' into 'main'
Who are we if not consistent?

See merge request cable-mc/cobblemon!1985
2025-12-19 07:36:21 +00:00
Konoha ce611cc61c cleanup: fix redundancies in form change sanitization 2025-12-18 21:17:48 -05:00
geumu 3df8dea71b Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-18 17:09:19 +00:00
geumu 3cca50b7cc Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-18 07:49:53 +00:00
geumu 1ff5622694 Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-18 06:01:40 +00:00
JazzMcNade f6ad7ff865 Fix changelog 2025-12-17 21:08:46 -06:00
JazzMcNade d69627a9c8 Merge branch 'main' into CombeeWorldGenFix 2025-12-17 20:05:09 -06:00
Alexis Salgueiro 411f388bd3 Translated using Weblate (French)
Currently translated at 99.5% (8984 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-12-18 00:21:32 +00:00
geumu 5b8d35604a Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-18 00:21:30 +00:00
geumu 619d002bc4 Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-17 07:19:25 +00:00
geumu 7049656f64 Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-16 06:33:05 +00:00
geumu e6e7c2982d Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-15 12:47:01 +00:00
JazzMcNade 54e8763470 Fixed a bug in which Combees could become stuck inside of leaves 2025-12-13 21:17:59 -06:00
JazzMcNade db34687df0 Merge branch 'main' into RestoreCombeeLeavesPathing 2025-12-13 21:11:57 -06:00
Konoha 7f008d85ff fix: form_change move updates no longer sanitize the sets of compounding property mons 2025-12-13 18:37:37 -05:00
Polymeta 06ebf51078 Merge branch 'Wii-Break-It-Wii-Fix-It' into 'main'
Boat Tags and Mint Leaves

Closes #1855

See merge request cable-mc/cobblemon!2082
2025-12-13 22:14:32 +00:00
Polymeta 39c5bcd73c Merge branch 'even-more-seasonings' into 'main'
Adding Missing Effects for Seasonings

See merge request cable-mc/cobblemon!1991
2025-12-13 22:13:24 +00:00
Ceejay 8f5f158b60 Adding Missing Effects for Seasonings 2025-12-13 22:13:24 +00:00
dhi_holo 3bc1e35125 Update CHANGELOG.md 2025-12-13 18:42:50 +10:00
dhi_holo 460bedddae Boat Tags
Resolves #1855
2025-12-13 18:12:24 +10:00
dhi_holo 8b64c315f3 Merge branch 'main' into Wii-Break-It-Wii-Fix-It 2025-12-13 17:51:15 +10:00
dhi_holo 7c824a2b72 OVERSIGHTS 2025-12-13 17:50:57 +10:00
Paul f197ac5077 Removed a bunch of duplicates from is_held_item because it looks whack. 2025-12-12 16:24:30 +10:00
Hiroku e0be669482 Merge branch 'patch-1' into 'main'
Fix Soothe Bell not tagged as `cobblemon:held/is_held_item`

See merge request cable-mc/cobblemon!2081
2025-12-12 06:17:17 +00:00
Watuneni iteite 82686b0511 Translated using Weblate (Japanese)
Currently translated at 99.4% (8976 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-12-12 03:20:38 +00:00
JPAKx4 f4eca30163 Fix merge issues 2025-12-11 10:40:53 -06:00
arvid6 2814183012 Translated using Weblate (Spanish)
Currently translated at 84.2% (7597 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-12-11 16:38:11 +00:00
JPAKx4 bbc3c2a8d6 Merge branch 'main' into default-offest
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/render/camera/MountedCameraRenderer.kt
2025-12-11 10:27:50 -06:00
geumu 7eeb7feeae Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-11 06:27:41 +00:00
geumu b2f850c1c8 Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-10 15:57:39 +00:00
Micky 08ea21fff4 Fix Soothe Bell not tagged as cobblemon:held/is_held_item 2025-12-10 13:27:23 +00:00
JazzMcNade 9dac604a93 Merge branch 'main' into RestoreCombeeLeavesPathing 2025-12-10 00:20:49 -06:00
Nico Merenq 23db346070 Translated using Weblate (Russian)
Currently translated at 77.7% (7012 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-12-09 19:49:13 +00:00
geumu d3b7d739bb Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-09 19:49:11 +00:00
Polymeta 28c0f8ab7d Merge branch 'item-interactions-sync' into 'main'
Item interactions sync

See merge request cable-mc/cobblemon!2068
2025-12-08 16:08:48 +00:00
lion fcbe0db568 Item interactions sync 2025-12-08 16:08:48 +00:00
Polymeta 83cefe476e Merge branch 'partner-mark' into 'main'
Add Partner Mark

See merge request cable-mc/cobblemon!2034
2025-12-08 15:57:21 +00:00
Guilherme Pereira 690ccbd260 refactor check riding statistics method for server player mixin 2025-12-08 12:06:20 -03:00
Polymeta 63846d53fb Merge branch 'main' into 'main'
Fixed shiny Pokémon not respecting the silent flag on spawn.

See merge request cable-mc/cobblemon!2064
2025-12-08 13:07:25 +00:00
Polymeta 86cb865742 fixed mochi items being consumed twice
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-12-08 13:01:14 +00:00
Polymeta 1a0c9b6a82 Merge branch 'malformed-jsons-no-more' into 'main'
Fixes a crash caused by malformed riding prespectives json file when trying to ride a pokemon

See merge request cable-mc/cobblemon!2077
2025-12-08 12:59:22 +00:00
Polymeta 985eb103fe Merge branch 'sterr/ride-sound-changes' into 'main'
New ride sound stuff

See merge request cable-mc/cobblemon!2065
2025-12-08 11:44:22 +00:00
Polymeta aec76a78da Merge branch 'restore_adorn_texturing' into 'main'
Restore adorn texturing

Closes #1833

See merge request cable-mc/cobblemon!2078
2025-12-08 11:36:41 +00:00
geumu eb6c134f4b Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-08 10:48:16 +00:00
Jacob Hartmann 17f3edf2be Changelog 2025-12-07 20:35:11 -07:00
Jacob Hartmann 9c5bfda20f Updating texture paths 2025-12-07 20:34:09 -07:00
geumu aa0b8d88e8 Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-07 12:09:09 +00:00
Gertimoshka 6d545fc1ca Fixes a crash caused by malformed riding prespectives json file when trying to ride a pokemon 2025-12-07 11:47:04 +02:00
Polymeta 9a8ad27122 Merge branch 'fix-spectator-crash' into 'main'
fix spectator crash

Closes #1847

See merge request cable-mc/cobblemon!2076
2025-12-07 08:39:18 +00:00
500-internal-server-error 9f1dbc9ff0 add notes to changelog 2025-12-07 07:58:55 +07:00
Polymeta 99942748b0 Merge branch 'entropydragon--spawn-bait-regional-forms' into 'main'
fix: use regional form data for spawn bait influence

See merge request cable-mc/cobblemon!2074
2025-12-07 00:49:48 +00:00
jasoncramer 64c34230bf chore: add to changelog 2025-12-06 19:28:41 -05:00
500-internal-server-error 36881b70be fix spectator crash 2025-12-06 20:51:48 +07:00
Deltric 3cf9425247 Fixed memory leak from battles not being cleaned up after ending. 2025-12-06 01:35:53 -06:00
jasoncramer 9b052478f6 fix: use regional form data for spawn bait influence 2025-12-05 14:23:05 -05:00
Hiroku 339f8339f0 Merge branch 'RestorePokemonItemPickup' into 'main'
Restore Pokemon item pickup

See merge request cable-mc/cobblemon!2073
2025-12-05 08:19:41 +00:00
Hiroku db9a802c3f Merge branch 'fix-spawner-crash' into 'main'
Prevents outside spawn influences from crashing the logical server.

See merge request cable-mc/cobblemon!2072
2025-12-05 07:45:29 +00:00
Carmendar b5578e72bd Merge branch 'main' into implement_pokemon 2025-12-05 01:30:51 -06:00
JazzMcNade e5666e7a82 Restore Pokemon item pickup. Remove unnecessary check in shouldBeSaved() 2025-12-05 01:30:20 -06:00
Carmendar 3aea0909a4 Merge branch 'main' into implement_pokemon 2025-12-05 01:27:25 -06:00
Teggy 5adef3336e Translated using Weblate (Spanish)
Currently translated at 84.2% (7597 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-12-05 06:23:53 +00:00
geumu 1a96b418bc Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-05 06:23:51 +00:00
geumu e373e86b60 Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-04 15:33:38 +00:00
geumu 6f3035184c Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-04 09:30:13 +00:00
Jerzykv 7ae8b1957c fixed Arcanine's texture having a line 2025-12-04 10:27:42 +01:00
Neovitalism a588213323 Update CHANGELOG.md 2025-12-04 03:05:03 -06:00
Neovitalism 56b2ba08ad Prevents outside influences from crashing the logical server.
Before when it was completed exceptionally w/ the pokesnack spawner, it would crash the server.
2025-12-04 03:03:57 -06:00
geumu 824b9718ee Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-04 08:07:32 +00:00
JazzMcNade 8540a73885 Fix for error occurring while populating bee nests with pokemon on world gen 2025-12-04 01:38:56 -06:00
Khvrram 7e6ca7be5e Merge branch cobblemon:main into main 2025-12-04 01:59:17 +00:00
geumu ef43f6c087 Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-03 21:23:55 +00:00
geumu c8a70caf79 Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-03 16:30:22 +00:00
Neovitalism 25ce784a60 Hopefully fixes changelog
Idk why gitlab didn't detect that when merging main
2025-12-03 10:17:48 -06:00
Neovitalism 5358cccb62 Merge branch 'main' into label-consistency 2025-12-03 10:09:41 -06:00
geumu ba11758e1f Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-03 12:53:16 +00:00
geumu f0412d6b1d Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-03 10:05:08 +00:00
Polymeta c43b3bbb4d Merge branch 'fix-can-drop-held-item' into 'main'
Fix can drop held item function

See merge request cable-mc/cobblemon!2069
2025-12-03 08:17:38 +00:00
lion d826aeeb07 Fix can drop held item function 2025-12-03 08:17:35 +00:00
Polymeta f90c6967ce Merge branch 'FixHoneyedLeavesInteraction' into 'main'
FixHoneyedLeavesInteraction

Closes #1832

See merge request cable-mc/cobblemon!2067
2025-12-03 08:15:26 +00:00
Jerzykv f5f87ce1a3 fixed Dewgong swimming in battle 2025-12-03 06:57:40 +01:00
Jerzykv f28b269734 fixed Camerupt jumping in battle 2025-12-03 06:57:31 +01:00
Jerzykv d545efd843 adjusted Tinkaton & Tinkatuff profile scaling 2025-12-03 06:57:07 +01:00
JazzMcNade b9cf18adbd Changelog 2025-12-02 20:16:56 -06:00
JazzMcNade 30650e1f9f Code simplication 2025-12-02 20:12:37 -06:00
JazzMcNade eaa558a7c8 Check for creative on using empty bottle 2025-12-02 00:36:53 -06:00
JazzMcNade 0dc725e513 Can only receive honey at max age. Adds result to hand if possible. Checks for creative and server/client 2025-12-02 00:28:23 -06:00
Zack the Ghast f8682c2123 Translated using Weblate (Portuguese (Brazil))
Currently translated at 98.2% (8866 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2025-12-02 05:47:12 +00:00
geumu f62e31a1eb Translated using Weblate (Korean)
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-02 05:46:50 +00:00
Watuneni iteite ea623b08a6 Translated using Weblate (Japanese)
Currently translated at 99.4% (8971 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-12-02 05:46:48 +00:00
Sterrezo a575c6bc3d Update CHANGELOG.md 2025-12-01 15:47:34 +01:00
Sterrezo 9c102a7850 Merge branch 'main' into sterr/ride-sound-changes 2025-12-01 15:45:40 +01:00
Sterrezo 22a1eaab19 Volume balancing 2025-12-01 15:35:22 +01:00
Sterrezo 0118ace5fc Implemented stereo flight loops 2025-12-01 15:09:37 +01:00
Sterrezo d4a93abbf7 Added support for submerged ride sounds 2025-12-01 14:27:55 +01:00
geumu ce3d5a413c Translated using Weblate (Korean)
Currently translated at 95.8% (8650 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-01 13:03:30 +00:00
Sterrezo d0ee3f3e9d Added an option for ride sounds to not play for the passengers 2025-12-01 13:56:56 +01:00
JazzMcNade 698fa9dff9 Merge branch 'main' into RestoreCombeeLeavesPathing 2025-12-01 00:46:50 -06:00
geumu d23fd6e23c Translated using Weblate (Korean)
Currently translated at 84.1% (7595 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-12-01 05:33:07 +00:00
Khvrram 46ae53f565 Merge branch cobblemon:main into main 2025-12-01 04:25:52 +00:00
Hiroku 7d4e5892ba Merge branch 'main' into 'main'
Orientation after crash fix

See merge request cable-mc/cobblemon!2061
2025-12-01 00:23:40 +00:00
Khvrram f9de415020 Orientation after crash fix 2025-12-01 00:23:39 +00:00
geumu 59395a254d Translated using Weblate (Korean)
Currently translated at 81.2% (7328 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-30 20:59:27 +00:00
geumu 5d7c6c8d6f Translated using Weblate (Korean)
Currently translated at 80.6% (7276 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-30 08:10:30 +00:00
Khurram Valiyev 4d123b6e4b Fixed shiny Pokémon not respecting the silent flag on spawn. 2025-11-29 22:50:52 -05:00
Polymeta 54dc2e7f6f tidy up changelog [skip-ci] 2025-11-29 12:57:24 +00:00
Polymeta 1d60ba093f Merge branch 'convention-tags-not-being-consistent-grrrrrrrr' into 'main'
Why

See merge request cable-mc/cobblemon!2060
2025-11-29 11:53:50 +00:00
Hiroku 0fef74dce7 Edit OneToOneFileStoreAdapter.kt 2025-11-29 09:46:27 +00:00
violet 6529293d21 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-29 02:44:47 -05:00
violet a1fce624ea something was forgotten in the changelog... 2025-11-29 02:44:34 -05:00
Hiroku b08647bb32 Revert "Merge branch 'main' into 'main'"
This reverts merge request !2062
2025-11-29 04:26:57 +00:00
Hiroku de9e89f040 Merge branch 'main' into 'main'
Editar en_us.json

See merge request cable-mc/cobblemon!2062
2025-11-29 04:25:10 +00:00
Ezequiel Neri Ferreira 84a29ebc2a Editar en_us.json 2025-11-29 04:22:49 +00:00
Paul 37b13ae959 Unsnaps your shot 2025-11-29 12:44:40 +10:00
dhi_holo 1cacbe8306 Why
It's called Shears, that's the item name, why does NeoForge use a Shear tag instead
Atleast Fabric has that tag as well so it's not a hard fix
2025-11-29 12:30:45 +10:00
Paul 12d224d15a Reinforce switchForm for crashes 2025-11-29 11:25:58 +10:00
Paul a57eee3afc Changelog updates [skip-ci] 2025-11-29 10:46:19 +10:00
geumu b7773f7471 Translated using Weblate (Korean)
Currently translated at 79.1% (7144 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-28 23:27:54 +00:00
Hiroku 57595c999c Merge branch 'remove-snapshot' into 'main'
Remove snapshot for release

See merge request cable-mc/cobblemon!2059
2025-11-28 23:24:59 +00:00
Landon Wills 83615b7eb3 Prepare release 2025-11-28 17:54:24 -05:00
Polymeta c53c544a8b Merge branch 'implement_pokemon' into 'main'
Last minute changes

See merge request cable-mc/cobblemon!2058
2025-11-28 22:23:03 +00:00
Kenji_64 c7c272c79c Had to fix Dragapult (again) 2025-11-28 21:04:50 +01:00
Kenji_64 c759161367 Added cries to Eelektrik and Eelektross 2025-11-28 21:01:27 +01:00
Landon 19b7b4804f Merge branch 'add-defend-owner-task' into 'main'
Make Pokémon only attack mobs targeting the player

See merge request cable-mc/cobblemon!2051
2025-11-28 18:30:05 +00:00
Landon 3a005cc813 Merge branch '1.7.1-spawns' into 'main'
Updated Dratini line spawns.

See merge request cable-mc/cobblemon!2055
2025-11-28 18:28:24 +00:00
Landon a8e16efa48 Merge branch 'jet-handling' into 'main'
Increase pitch rotation of Jet

See merge request cable-mc/cobblemon!2054
2025-11-28 18:08:20 +00:00
Veraxiel c3ddfce0a7 Updated Dratini spawn. 2025-11-28 12:38:53 -05:00
Landon Wills 9500f7a1f3 adjust wording 2025-11-28 12:21:44 -05:00
Landon Wills 83a8d92e3f Add changelog 2025-11-28 12:21:08 -05:00
Landon Wills e105c5d4d7 Remove multipliers, adjust expression 2025-11-28 12:17:42 -05:00
Landon Wills 3d816f57e2 Increase pitch rotation of Jet 2025-11-28 12:13:55 -05:00
Landon 1e6dcfba9b Merge branch 'change-freelook-default' into 'main'
Change free look binding default to Left Alt

See merge request cable-mc/cobblemon!2053
2025-11-28 16:30:35 +00:00
Polymeta e59d755d32 Merge branch 'implement_pokemon' into 'main'
Various implementation fixes

See merge request cable-mc/cobblemon!2050
2025-11-28 15:38:40 +00:00
geumu f927e47bfe Translated using Weblate (Korean)
Currently translated at 77.9% (7030 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ko/
2025-11-28 15:25:08 +00:00
Watuneni iteite 48a37b2018 Translated using Weblate (Japanese)
Currently translated at 99.2% (8953 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-28 15:25:07 +00:00
Guilherme Pereira c155b5575d change free look binding default to left alt 2025-11-28 09:35:13 -03:00
Jerzykv 9c6b8b231a oops 2 2025-11-28 13:30:16 +01:00
Jerzykv 92b404dac4 oops 2025-11-28 13:27:19 +01:00
Jerzykv 8a1c536d68 Fixed Furfrou's pink and magenta trims being swapped 2025-11-28 12:56:07 +01:00
Jerzykv 04719d22a5 Fixed a tiny issue with Ceruledge's poser 2025-11-28 12:55:54 +01:00
Jerzykv dacc312756 Implemented Tinkatink line remodels 2025-11-28 12:55:26 +01:00
Polymeta ee4a3d46ba Merge branch '1.7.1-spawns' into 'main'
Updated some spawns.

See merge request cable-mc/cobblemon!2052
2025-11-28 09:31:16 +00:00
violet 80b11f1c3d Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-28 01:20:00 -05:00
Carmendar ddcf4eea7b Heracross and Mudsdale jump fix. 2025-11-28 00:16:50 -06:00
violet 6a0681e4c6 fixed cyclizar's textures 2025-11-27 23:37:39 -05:00
Veraxiel 8ebb378da7 Updated some spawns. 2025-11-27 23:31:32 -05:00
violet e92a878074 fixed boltund's model 2025-11-27 23:30:22 -05:00
Paul 0b97b41c08 Merge remote-tracking branch 'origin/main' 2025-11-28 12:27:10 +10:00
Paul 20fe732cfc Potentially minor perf improvement on following walk targets that are unreachable 2025-11-28 12:26:26 +10:00
Carmendar 0575aa29d9 Doubled high end land mount stamina. 2025-11-27 18:43:20 -06:00
Guilherme Pereira 29b560d244 Merge branch 'main' of gitlab.com:cable-mc/cobblemon into partner-mark 2025-11-27 18:21:19 -03:00
Guilherme Pereira dcc98b4a54 rename mob to living entity 2025-11-27 18:19:49 -03:00
Guilherme Pereira d3ce455391 prevents defend owner task from targeting players 2025-11-27 18:10:59 -03:00
Kenji_64 85c6b633d8 Fixed Dragapult's eyes clippings 2025-11-27 22:03:48 +01:00
Guilherme Pereira 956b599060 update CHANGELOG.md 2025-11-27 17:51:11 -03:00
Jerzykv f88552f99b Gholdengo no longer dances in air. what a shame (fixed flying battle pose issue) 2025-11-27 21:46:35 +01:00
Carmendar e2b559f3eb Merge branch 'main' into implement_pokemon 2025-11-27 14:42:31 -06:00
Carmendar 39816d33b6 Rufflet eepy cry and battle pose fix 2025-11-27 14:38:39 -06:00
Landon 0cf2a23fd4 Merge branch 'cobble-land-fixes' into 'main'
Land adjustments for a smoother riding experience. And bug fixes to land rides

See merge request cable-mc/cobblemon!2039
2025-11-27 19:31:24 +00:00
Guilherme Pereira c4d8eae47e add defend owner task once again 2025-11-27 12:16:54 -03:00
Polymeta 2a5a292386 fix saccharine hanging signs sometimes dropping oak wood signs
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-11-27 11:27:58 +00:00
阿鱼 f6b2da6ed6 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9022 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-27 11:09:47 +00:00
Polymeta e8a09f5c48 Merge branch 'json-fixing' into 'main'
JSON Fixes

Closes #1819

See merge request cable-mc/cobblemon!2048
2025-11-27 10:42:07 +00:00
dhi_holo e82193cdfd Update interact_with_pokemon.json
Removed accidental flag
2025-11-27 19:56:33 +10:00
dhi_holo 87e7cdebf6 Fabric Tags that aren't true c tags are the bane of my existence
Fixed the concrete tags to behave properly, changelog
2025-11-27 15:25:53 +10:00
dhi_holo 9ca84d852f Update interact_with_pokemon.json
Should close #1819
2025-11-27 14:22:06 +10:00
Carmendar 8194f93d13 Merge branch 'main' into implement_pokemon 2025-11-26 20:54:41 -06:00
Carmendar c158ec33fa Braviary sleep cry fix 2025-11-26 20:53:46 -06:00
Carmendar 1e27c7494e Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2025-11-26 20:52:27 -06:00
Carmendar 54a1f8d932 Braviary battle pose fix 2025-11-26 20:51:45 -06:00
Watuneni iteite 275779b20e Translated using Weblate (Japanese)
Currently translated at 99.2% (8953 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-11-26 22:24:14 +00: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
Hiroku b5098a2ad0 Fixed JVM crash from campfire pot 2025-11-26 21:40:29 +00:00
阿鱼 2102f8ff88 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 99.6% (8991 of 9022 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-11-26 15:42:52 +00:00
Kenji_64 d2af0c9332 Fixed Swampert line's missing recoils crashing the game 2025-11-26 15:40:40 +01: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
Neovitalism 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
Kenji_64 379a566d71 Fixed Ditto being silent 2025-11-26 11:52:43 +01:00
Kenji_64 f30ff739ed Fixed Metagross' ground_idle not looping properly (again) >:( 2025-11-26 11:36:23 +01:00
阿鱼 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 a8949cf1f9 changelog 2025-11-25 21:49:38 -06:00
JazzMcNade 24fe1c125c changelog 2025-11-25 21:47:45 -06:00
JazzMcNade 61db6334f9 Restores Combee pathing through leaves 2025-11-25 21:37:57 -06:00
JazzMcNade 023160f87a Removed a really silly cast 2025-11-25 21:32:17 -06:00
RedGenesectNinja c45e34648c Fixed Toedscool and Toedscruel's hitboxes being too small 2025-11-25 18:53:12 -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
阿鱼 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 iteite 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
jackowes d56586ecac - Fix walking animation issues 2025-11-24 21:39:36 -06: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
阿鱼 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
jackowes 9df8be33e9 - revert a bad change 2025-11-24 14:51:33 -06:00
Alexis Salgueiro 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
lion 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
jackowes ff2afd546e changelog 2025-11-23 21:50:30 -06:00
Test b95900b29a Fix PC crash with VulkanMod 2025-11-23 22:39:28 -05:00
jackowes b8b7756a45 - Add double tap to sprint on land mounts
- Adjust step up in air and on ground to reflect vanilla behaviour
- Fix inAir check so pose does not change back to walking or running while in air
2025-11-23 21:29:30 -06:00
jackowes 3d6146f551 - Add double tap to sprint on land mounts.
- Adjust step up in air and on ground to reflect vanilla behaviour
2025-11-23 21:15:41 -06: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
jackowes 31d81db243 Merge branch 'main' into cobble-land-fixes 2025-11-23 18:19:51 -06:00
jackowes 4c36db8685 - Fix ridden pokemon land collision and weird step up issues. Horse is smoother overall now.
- Change the turnrate debuff to be squareroot instead of linear.
- Accel stat does not affect land ridden mounts walks.
- Add vanilla sprinting fov to pokemon land mounts
2025-11-23 18:19:13 -06:00
washashu0905 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
阿鱼 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 Ghast 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
Guilherme Pereira 7cedfb9047 update CHANGELOG.md 2025-11-22 22:02:14 -03:00
Guilherme Pereira a7ab2e37c2 Merge branch 'main' of gitlab.com:cable-mc/cobblemon into partner-mark 2025-11-22 21:57:49 -03:00
Guilherme Pereira 4723f91500 add riding stats 2025-11-22 21:57:25 -03: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
Guilherme Pereira e23aa6b066 add partner mark molang callback 2025-11-22 19:39:21 -03: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
geumu 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 iteite 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
geumu 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 iteite 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
geumu 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 iteite 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
geumu 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 iteite 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 iteite 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
geumu 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 iteite 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 Merenq 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
阿鱼 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
geumu 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 iteite 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
geumu 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
lion 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
geumu 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
geumu 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
lion 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 iteite 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
Teggy 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
阿鱼 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
geumu 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
JPAKx4 8f462aab40 Add default_seat option to seat offset posers, and remove shouldRotate as it's not needed for positioning the camera. 2025-11-18 00:56:40 -06: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
Neovitalism 46d278ca55 key \:) 2025-11-17 03:18:02 -06: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
Neovitalism 339038956d Support for deserialization from any key
...I think.
2025-11-17 03:09:21 -06: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
lion 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
lion 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
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
Neovitalism 116a93d8cc Update CHANGELOG.md 2025-11-16 04:19:32 -06:00
Neovitalism acebc35d3f Who are we if not consistent?
Before, this property was called `PokemonFlagProperty`, had the key `tag`, and checked pokémon's labels. It was also in a package by itself.

Now, it's moved down into the properties package, renamed to LabelProperty, and the key "label" was added, keeping "tag" as a secondary for those that are using it currently.
2025-11-16 04:10:45 -06: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
JPAKx4 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
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
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
Kenji_64 33a4e31b60 Fixed Wartortle's shiny shell not being green 2025-11-15 19:51:14 +01:00
Nico Merenq 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 Guy 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 Merenq 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ño 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
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 Merenq 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 Puerari 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
geumu 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 Ghast 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 iteite 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
Yasito 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
Yasito 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_holo 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 Merenq 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_holo 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
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
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
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
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
Konoha aee89f1c92 Preliminary Bag Clause implementation 2025-09-09 18:15:37 -04: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
384 changed files with 2264 additions and 5734 deletions

No files matched your search

-30
View File
@@ -2,11 +2,7 @@
## [1.7.4 (MONTH Xth, 2026)](#1-7-4)
### 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
@@ -17,42 +13,16 @@
### Animation updates for the following Pokémon
### 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)
### 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
### 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
### Localization
- Updated translations for:
+1
View File
@@ -6,6 +6,7 @@
- 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.
+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)
@@ -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();
@@ -313,7 +313,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;
@@ -94,61 +89,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());
}
}
@@ -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
@@ -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> {
@@ -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
@@ -255,11 +253,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 +276,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()
@@ -502,7 +483,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))
@@ -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.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
}
}
}
}
}
@@ -124,8 +124,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) ->
@@ -525,7 +505,6 @@ open class PokemonBattle(
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 +512,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 } }
@@ -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>()
@@ -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 }
)
}
@@ -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
@@ -872,8 +871,6 @@ object MoLangFunctions {
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 +891,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,30 +1830,6 @@ 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) {
@@ -2059,13 +2023,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") {
@@ -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)
}
}
}
@@ -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
@@ -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,
@@ -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,
)
)
)
}
}
}
@@ -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)
)
}
}
}
@@ -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
@@ -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()
}
}
@@ -31,6 +31,7 @@ import kotlin.collections.associateWith
import kotlin.collections.partition
import kotlin.math.absoluteValue
/**
* AI that tries to choose the best move for the given situations. Based off of the Pokemon Trainer Tournament Simulator Github
* https://github.com/cRz-Shadows/Pokemon_Trainer_Tournament_Simulator/blob/main/pokemon-showdown/sim/examples/Simulation-test-1.ts#L330
@@ -48,7 +49,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 +219,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 +259,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,6 +270,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
if (checkSwitchOutSkill() && shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
considerSwitching(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, availableSwitches, battle, aiSide)
}
activeTrackerPokemon.firstTurn = false
// 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)) {
@@ -289,6 +296,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 +315,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 +324,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 +356,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 +372,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 +383,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 +391,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 +404,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 +431,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 +460,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 +520,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
@@ -527,7 +532,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
// 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
val improvementThreshold = currentScore.absoluteValue * 0.25 + 2
if (bestSwitchScore <= currentScore + improvementThreshold) {
return false
}
@@ -562,7 +567,7 @@ 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 } ||
@@ -990,4 +995,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 } }
@@ -51,7 +51,6 @@ 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))
battle.getActorAndActiveSlotFromPNX(pnx).second.battlePokemon = null
@@ -110,9 +110,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].
*/
@@ -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()
@@ -151,15 +151,13 @@ class CampfireBlock(settings: Properties, val isSoul: Boolean) : BaseEntityBlock
override fun placeLiquid(level: LevelAccessor, pos: BlockPos, state: BlockState, fluidState: FluidState): Boolean {
val blockEntity = level.getBlockEntity(pos)
if (fluidState.type === Fluids.WATER && blockEntity is CampfireBlockEntity) {
if (level is Level) {
if (!level.isClientSide) {
removePotItem(blockEntity, state, level, pos, null, true)
level.playSoundServer(pos.center, SoundEvents.GENERIC_EXTINGUISH_FIRE, SoundSource.BLOCKS, 1.0F, 1.0F)
}
if (level.isClientSide) for (i in 0..19) MCCampfireBlock.makeParticles(level, pos, false, true)
if (!level.isClientSide) {
removePotItem(blockEntity, state, level as Level, pos, null, true)
level.playSoundServer(pos.center, SoundEvents.GENERIC_EXTINGUISH_FIRE, SoundSource.BLOCKS, 1.0F, 1.0F)
}
if (level.isClientSide) for (i in 0..19) MCCampfireBlock.makeParticles(level as Level, pos, false, true)
level.scheduleTick(pos, fluidState.type, fluidState.type.getTickDelay(level))
return true
} else {
@@ -65,9 +65,6 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
private val growthPoints = arrayListOf<ResourceLocation>()
var mulchVariant = MulchVariant.NONE
// For Random Tick compensation: records the game time of last tick
var lastTickTime: Long = 0L
/**
* The idea behind the growth point sequence is it's a 16-long string of
* hexadecimal numbers. They represent the order of the growth points that
@@ -270,7 +267,6 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
} catch (ignored: ResourceLocationException) {}
}
this.mulchDuration = nbt.getInt(MULCH_DURATION)
this.lastTickTime = nbt.getLong(LAST_TICK_TIME)
this.wasLoading = false
if (nbt.contains(GROWTH_POINTS_SEQUENCE)) {
growthPointSequence = nbt.getString(GROWTH_POINTS_SEQUENCE)
@@ -291,7 +287,6 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
nbt.putInt(MULCH_DURATION, mulchDuration)
nbt.putString(GROWTH_POINTS_SEQUENCE, growthPointSequence)
nbt.putString(MULCH_VARIANT, mulchVariant.toString())
nbt.putLong(LAST_TICK_TIME, lastTickTime)
}
override fun setChanged() {
@@ -351,39 +346,24 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
return
}
/**
* Process Random Tick compensation logic.
* Calculates elapsed time since last tick and batch-decrements stageTimer.
*/
fun processTick(world: ServerLevel, pos: BlockPos, state: BlockState): Boolean {
if (state.getValue(BerryBlock.IS_ROOTED)) return false
val currentTime = world.gameTime
val elapsed = if (lastTickTime > 0L) {
(currentTime - lastTickTime).toInt().coerceAtLeast(1)
} else {
1 // First tick, only decrement by 1
}
lastTickTime = currentTime
// Batch decrement the timer
if (stageTimer > 0) {
stageTimer = (stageTimer - elapsed).coerceAtLeast(0)
}
// Return whether growth is needed
return stageTimer <= 0
}
//Using a similar approach to ComputerCraft, implement this client side
interface RenderState : AutoCloseable {
var needsRebuild: Boolean
}
companion object {
internal val TICKER = BlockEntityTicker<BerryBlockEntity> { world, pos, state, blockEntity ->
if (world.isClientSide) return@BlockEntityTicker
if (state.getValue(BerryBlock.IS_ROOTED)) return@BlockEntityTicker
if (blockEntity.stageTimer >= 0) {
blockEntity.stageTimer--
}
if (blockEntity.stageTimer <= 0) {
(state.block as BerryBlock).growHelper(world as ServerLevel, world.random, pos, state)
}
}
//private const val LIFE_CYCLES = "life_cycles"
private const val GROWTH_POINTS = "GrowthPoints"
private const val LAST_TICK_TIME = "LastTickTime"
private const val GROWTH_POINTS_SEQUENCE = "GrowthPointsSequence"
private const val GROWTH_TIMER = "GrowthTimer"
private const val STAGE_TIMER = "StageTimer"
@@ -29,7 +29,6 @@ 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.position.SpawnablePosition
import com.cobblemon.mod.common.api.spawning.spawner.FixedAreaSpawner
import com.cobblemon.mod.common.api.spawning.spawner.PokeSnackSpawnerFactory
import com.cobblemon.mod.common.block.PokeSnackBlock
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.item.components.BaitEffectsComponent
@@ -63,22 +62,41 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
}
val spawner: FixedAreaSpawner by lazy {
val server = level as ServerLevel
val baitEffects = getBaitEffects()
val ctx = PokeSnackSpawnerFactory.Context(
world = server,
pos = blockPos,
FixedAreaSpawner(
name = "poke_snack_spawner_${level?.dimension()?.location()}}_$blockPos",
spawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL,
world = level as ServerLevel,
position = blockPos,
horizontalRadius = RADIUS,
verticalRadius = RADIUS,
maxPokemonPerChunk = Cobblemon.config.pokeSnackPokemonPerChunk,
name = "poke_snack_spawner_${server.dimension().location()}_$blockPos",
baitEffects = baitEffects
)
maxPokemonPerChunk = Cobblemon.config.pokeSnackPokemonPerChunk
).also {
it.influences.add(this)
PokeSnackSpawnerFactory.create(ctx).also { spawner ->
spawner.influences.add(this)
val baitEffects = getBaitEffects()
val stackedLureTier = baitEffects
.filter { it.type == SpawnBait.Effects.RARITY_BUCKET }
.sumOf { it.value }
.toInt()
if (stackedLureTier > 0) {
it.influences += BucketNormalizingInfluence(
tier = stackedLureTier,
gradient = 0.2F,
firstTier = 1.2F
)
}
it.influences += BucketMultiplyingInfluence(
mapOf(
"uncommon" to 2.25f,
"rare" to 5.5f,
"ultra-rare" to 5.5f,
)
)
it.influences += SpawnBaitInfluence(effects = baitEffects)
}
}
@@ -24,7 +24,7 @@ import com.cobblemon.mod.common.block.entity.TintBlockEntity
import com.cobblemon.mod.common.client.battle.ClientBattle
import com.cobblemon.mod.common.client.gui.PartyOverlay
import com.cobblemon.mod.common.client.gui.PartyOverlayDataControl
import com.cobblemon.mod.common.client.gui.RideControlsOverlay
import com.cobblemon.mod.common.client.gui.RideOverlay
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
import com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts
@@ -112,7 +112,7 @@ object CobblemonClient {
val overlay: PartyOverlay by lazy { PartyOverlay() }
val battleOverlay: BattleOverlay by lazy { BattleOverlay() }
val pokedexUsageContext: PokedexUsageContext by lazy { PokedexUsageContext() }
val rideControlsOverlay: RideControlsOverlay by lazy { RideControlsOverlay() }
val rideControlsOverlay: RideOverlay by lazy { RideOverlay() }
fun onLogin() {
clientPlayerData = ClientGeneralPlayerData()
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.gui.drawPosablePortrait
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.darkGray
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.text
@@ -230,7 +229,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
var levelScrollOffset = 0F
var levelScrollPositionOffset = 0F
var levelScrollSize = 17F
if (expGainedData?.oldLevel != null) {
if (expGainedData != null && expGainedData.oldLevel != null) {
val ticksWithDelta = (expGainedData.ticks + partialDeltaTicks) - (PartyOverlayDataControl.BAR_UPDATE_BEFORE_TIME + PartyOverlayDataControl.BAR_FLASH_TIME)
val transition = ticksWithDelta / PartyOverlayDataControl.LEVEL_UP_PORTRAIT_TIME
if ((0F..<1F).contains(transition)) {
@@ -404,48 +403,10 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
blue = expBlue
)
//Handling EXP Text
var expGained = 0
var expTextTransparency = 0F
var expTextOffset = 0F
if (expGainedData != null) {
expGained = expGainedData.expGained
val ticksWithDelta = expGainedData.ticks + partialDeltaTicks
if (ticksWithDelta <= PartyOverlayDataControl.EXP_POPUP_TIME.fadeIn) {
val transition = ticksWithDelta / PartyOverlayDataControl.EXP_POPUP_TIME.fadeIn
val step = (floor(transition * 3)) + 1
expTextTransparency = step * 0.25F
expTextOffset = 4 - step
} else if (ticksWithDelta <= PartyOverlayDataControl.EXP_POPUP_TIME.fadeIn + PartyOverlayDataControl.EXP_POPUP_TIME.hold) {
expTextTransparency = 1F
expTextOffset = 0F
} else {
val adjustedTicks = ticksWithDelta - (PartyOverlayDataControl.EXP_POPUP_TIME.fadeIn + PartyOverlayDataControl.EXP_POPUP_TIME.hold)
val transition = adjustedTicks / PartyOverlayDataControl.EXP_POPUP_TIME.fadeOut
val step = (floor(transition * 3)) + 1
expTextTransparency = 1F - (step * 0.25F)
expTextOffset = -step
}
}
if (expTextTransparency > 0) {
drawScaledText(
context = context,
text = lang("ui.exp.number", expGained.toString()).bold(),
x = panelX + selectedOffsetX + 57F,
y = indexY + 17F + expTextOffset,
scale = SCALE,
shadow = true,
opacity = expTextTransparency
)
}
//Handling Popups
var ticksForMove = -1F
var ticksForEvo = -1F
//Handling Popups
if (expGainedData != null) {
val ticksWithDelta = expGainedData.ticks + partialDeltaTicks
val ticks = ticksWithDelta - (PartyOverlayDataControl.BAR_UPDATE_BEFORE_TIME + PartyOverlayDataControl.BAR_FLASH_TIME)
@@ -476,7 +437,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
return 0F to 1F
} else {
val adjustedPopupTicks = ticks - (PartyOverlayDataControl.POPUP_TIME.fadeIn + PartyOverlayDataControl.POPUP_TIME.hold)
val transition = adjustedPopupTicks / PartyOverlayDataControl.POPUP_TIME.fadeOut
val transition = adjustedPopupTicks / PartyOverlayDataControl.POPUP_TIME.fadeIn
val step = (floor(transition * 3)) + 1
return (-step) to (1F - (step * 0.25F))
}
@@ -490,7 +451,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
blitk(
matrixStack = matrices,
texture = newEvoPopup,
x = (panelX + selectedOffsetX + (if (expTextTransparency > 0 && movePopupTransparency > 0) 78F else 56.5F)) / SCALE,
x = (panelX + selectedOffsetX + 56.5F) / SCALE,
y = (indexY + 4 + evoPopupYOffset) / SCALE,
width = 37,
height = 20,
@@ -503,7 +464,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
matrixStack = matrices,
texture = newMovesPopup,
x = (panelX + selectedOffsetX + 56.5F) / SCALE,
y = (indexY + (if (expTextTransparency > 0) 4 else 17) + movePopupYOffset) / SCALE,
y = (indexY + 17 + movePopupYOffset) / SCALE,
width = 37,
height = 20,
scale = SCALE,
@@ -19,10 +19,10 @@ object PartyOverlayDataControl {
const val BAR_UPDATE_BEFORE_TIME = 15
const val BAR_UPDATE_AFTER_TIME = 15
const val BAR_FLASH_TIME = 2
const val BAR_UPDATE_NO_LEVEL_TIME = BAR_UPDATE_BEFORE_TIME + BAR_UPDATE_AFTER_TIME + BAR_FLASH_TIME
val POPUP_TIME = FadeTimings(3, 40, 3)
const val LEVEL_UP_PORTRAIT_TIME = 10
val EXP_POPUP_TIME = FadeTimings(3, BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total() - 6, 3)
val BAR_UPDATE_NO_LEVEL_TIME = BAR_UPDATE_BEFORE_TIME + BAR_UPDATE_AFTER_TIME + BAR_FLASH_TIME
private enum class RenderTarget {
NONE,
@@ -35,19 +35,21 @@ object PartyOverlayDataControl {
private var barFillupSound: SoundInstance? = null
private var levelUpJingleSound: SoundInstance? = null
private var levelUpJingleSoundType: SoundEvent? = null
fun pokemonGainedExp(pokemonUuid : UUID, oldLevel: Int?, expGained: Int, countOfMovesLearned: Int, countOfEvosUnlocked: Int = 0) {
var time = BAR_UPDATE_NO_LEVEL_TIME
if (countOfMovesLearned > 0 || countOfEvosUnlocked > 0) {
time = BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total()
}
val data = overlayData[pokemonUuid]
val newData = ExpGainedData(oldLevel, expGained, countOfMovesLearned, countOfEvosUnlocked).also { it.ticksMax = BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total() }
val newData = ExpGainedData(oldLevel, expGained, countOfMovesLearned, countOfEvosUnlocked).also { it.ticksMax = time }
if (data != null) {
if (data.movesGainedData != null) { //Absorb Data
if (data.movesGainedData != null) {
newData.countOfMovesLearned += data.movesGainedData!!.movesCount
data.movesGainedData = null
}
if (data.evoGainedData != null) { //Absorb Data
if (data.evoGainedData != null) {
newData.countOfEvosUnlocked += data.evoGainedData!!.evolutionCount
data.evoGainedData = null
}
val expData = data.expGainedData
@@ -70,7 +72,8 @@ object PartyOverlayDataControl {
val data = overlayData[pokemonUuid]
val newData = EvolutionGainedData(evoCount).also { it.ticksMax = POPUP_TIME.total() }
if (data != null) {
if (data.expGainedData != null) {
if (data.expGainedData != null && data.expGainedData!!.ticks < BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME) {
data.expGainedData!!.ticksMax = BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total()
data.expGainedData!!.countOfEvosUnlocked += evoCount
return
}
@@ -90,7 +93,8 @@ object PartyOverlayDataControl {
val data = overlayData[pokemonUuid]
val newData = MovesGainedData(movesCount).also { it.ticksMax = POPUP_TIME.total() }
if (data != null) {
if (data.expGainedData != null) {
if (data.expGainedData != null && data.expGainedData!!.ticks < BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME) {
data.expGainedData!!.ticksMax = BAR_UPDATE_BEFORE_TIME + BAR_FLASH_TIME + POPUP_TIME.total()
data.expGainedData!!.countOfMovesLearned += movesCount
return
}
@@ -133,28 +137,13 @@ object PartyOverlayDataControl {
fun tick(paused: Boolean) {
val deletion = mutableListOf<UUID>()
if (paused) return
if (levelUpJingleSound != null && !Minecraft.getInstance().soundManager.isActive(levelUpJingleSound!!)) {
levelUpJingleSound = null
levelUpJingleSoundType = null
}
overlayData.forEach { (id, data) ->
if (data.expGainedData != null) { // We update this in order and render these in order, and as such we don't tick others
val expGainedData = data.expGainedData!!
expGainedData.ticks += 1
if (expGainedData.ticks == BAR_UPDATE_BEFORE_TIME && expGainedData.oldLevel != null) {
if (expGainedData.countOfEvosUnlocked > 0) {
stopSound(levelUpJingleSound)
levelUpJingleSound = playSound(CobblemonSounds.EVOLUTION_NOTIFICATION)
levelUpJingleSoundType = CobblemonSounds.EVOLUTION_NOTIFICATION
} else {
if (levelUpJingleSoundType != CobblemonSounds.EVOLUTION_NOTIFICATION) {
stopSound(levelUpJingleSound)
levelUpJingleSound = playSound(CobblemonSounds.LEVELUP)
levelUpJingleSoundType = CobblemonSounds.LEVELUP
}
}
stopSound(levelUpJingleSound)
levelUpJingleSound = playSound(CobblemonSounds.LEVELUP)
}
if (expGainedData.ticks >= expGainedData.ticksMax) {
data.expGainedData = null
@@ -177,7 +166,6 @@ object PartyOverlayDataControl {
}
if (getCurrentRenderTarget(id) == RenderTarget.NONE) deletion.add(id)
}
deletion.forEach {
overlayData.remove(it)
}
@@ -228,7 +216,7 @@ object PartyOverlayDataControl {
//SOUNDS
private fun playSound(soundEvent: SoundEvent): SoundInstance? {
if (!PartyOverlay.canRender()) return null
val soundInstance = SimpleSoundInstance.forUI(soundEvent, 1F, 1F)
val soundInstance = SimpleSoundInstance.forUI(soundEvent, 1F)
Minecraft.getInstance().soundManager.play(soundInstance)
return soundInstance
}
@@ -47,7 +47,6 @@ fun drawProfilePokemon(
a: Float = 1F,
headYaw: Float = 0f,
headPitch: Float = 0f,
blockLight: Int = 13
) = drawProfilePokemon(
species = renderablePokemon.species.resourceIdentifier,
matrixStack = matrixStack,
@@ -64,7 +63,6 @@ fun drawProfilePokemon(
a = a,
headYaw = headYaw,
headPitch = headPitch,
blockLight = blockLight
)
fun drawProfilePokemon(
@@ -84,7 +82,6 @@ fun drawProfilePokemon(
a: Float = 1F,
headYaw: Float = 0f,
headPitch: Float = 0f,
blockLight: Int = 13
) {
RenderSystem.applyModelViewMatrix()
matrixStack.scale(scale, scale, -scale)
@@ -141,7 +138,7 @@ fun drawProfilePokemon(
val light1 = Vector3f(-1F, 1F, 1.0F)
val light2 = Vector3f(1.3F, -1F, 1.0F)
RenderSystem.setShaderLights(light1, light2)
val packedLight = LightTexture.pack(blockLight, 0)
val packedLight = LightTexture.pack(11, 7)
val colour = toHex(r, g, b, a)
model.withLayerContext(bufferSource, state, VaryingModelRepository.getLayers(species, state)) {
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.client.gui
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
import com.cobblemon.mod.common.api.riding.behaviour.types.air.*
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeState
@@ -19,6 +21,7 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinBehaviour
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinState
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asTranslated
@@ -30,17 +33,28 @@ import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.ChatScreen
import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.player.Input
import net.minecraft.client.player.LocalPlayer
import net.minecraft.client.renderer.BiomeColors
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.FastColor
import net.minecraft.util.Mth
import net.minecraft.world.entity.Entity
import net.minecraft.world.level.BlockAndTintGetter
import kotlin.math.floor
import kotlin.math.max
import kotlin.math.round
class RideControlsOverlay : Gui(Minecraft.getInstance()) {
class RideOverlay : Gui(Minecraft.getInstance()) {
companion object {
private const val CONTROLS_FADE_FRAMES = 20F
private const val BASELINE_FPS = 60F
private const val MOTION_FADE_FRAMES = 10
private const val MOTION_FRAMES = 10
private const val MOTION_OVERLAY_MAX_OPACITY = 0.6F
private const val HALF_SCALE = 0.5F
private val mouseResource = cobblemonResource("textures/gui/riding/mouse.png")
@@ -59,6 +73,8 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
private val keyJumpResource = cobblemonResource("textures/gui/riding/key_jump.png")
private val keySneakWideResource = cobblemonResource("textures/gui/riding/key_sneak_wide.png")
private val keyJumpWideResource = cobblemonResource("textures/gui/riding/key_jump_wide.png")
private val motionLinesResource = cobblemonResource("textures/gui/riding/motion_lines_overlay.png")
}
private val screenExemptions: List<Class<out Screen>> = listOf(ChatScreen::class.java)
@@ -67,6 +83,9 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
private var controlsDurationFrames = controlsMaxDurationFrames
private var controlsFadeFrames = CONTROLS_FADE_FRAMES
private var motionFrameIntervals = 0F
private var motionFadeFrames = 0
private var lastMouseX = 0
private var lastMouseY = 0
@@ -81,43 +100,70 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
override fun render(context: GuiGraphics, tickCounter: DeltaTracker) {
val minecraft = Minecraft.getInstance()
// Hiding if a Screen is open and not exempt
minecraft.screen?.let { screen ->
if ((!screenExemptions.contains(screen.javaClass as Class<out Screen>))) return
}
if (minecraft.options.hideGui || minecraft.debugOverlay.showDebugScreen()) return
minecraft.player?.let { player ->
// Hiding if a Screen is open and not exempt
minecraft.screen?.let { screen ->
if ((!screenExemptions.contains(screen.javaClass as Class<out Screen>))) return
}
if (minecraft.options.hideGui || minecraft.debugOverlay.showDebugScreen()) return
val riddenEntity = player.vehicle
if (riddenEntity != null && riddenEntity is PokemonEntity) {
// Only show controls to driver
if (riddenEntity === player.controlledVehicle) {
renderControls(minecraft, context, tickCounter, riddenEntity)
}
val ridingBehaviourSettings = riddenEntity.ridingController?.context?.settings ?: return
val ridingBehaviourState = riddenEntity.ridingController?.context?.state ?: return
setCurrentRideBehaviour(ridingBehaviourSettings, ridingBehaviourState)
val tickDelta = tickCounter.realtimeDeltaTicks.takeIf { !minecraft.isPaused } ?: 0F
val updateInterval = (tickDelta / 20F) * BASELINE_FPS
renderMotionOverlay(minecraft, player, riddenEntity, context, updateInterval, ridingBehaviourSettings, ridingBehaviourState)
renderRideControls(minecraft, context, updateInterval, ridingBehaviourSettings, ridingBehaviourState)
} else {
resetControlsOverlayState()
}
}
}
private fun renderControls(minecraft: Minecraft, context: GuiGraphics, tickCounter: DeltaTracker, riddenEntity: PokemonEntity) {
// Update max duration if user has changed config
val configDuration = Cobblemon.config.displayControlSeconds * BASELINE_FPS
if (controlsMaxDurationFrames != configDuration) {
controlsMaxDurationFrames = configDuration
resetControlsOverlayState()
fun renderMotionOverlay(minecraft: Minecraft, player: LocalPlayer, riddenEntity: Entity, context: GuiGraphics, updateInterval: Float, ridingBehaviourSettings: RidingBehaviourSettings, ridingBehaviourState: RidingBehaviourState) {
if (currentBehaviourKey == JetBehaviour.KEY || currentBehaviourKey == DolphinBehaviour.KEY) {
val isBoosting = if (currentBehaviourKey == JetBehaviour.KEY) (ridingBehaviourState as JetState).boosting.get()
else (ridingBehaviourState as DolphinState).boosting.get()
val interval = round(updateInterval).toInt()
motionFadeFrames = (motionFadeFrames + (interval * (if (isBoosting) 1 else -1))).coerceIn(0, MOTION_FADE_FRAMES)
val opacity = (motionFadeFrames * (1F / MOTION_FADE_FRAMES)).coerceIn(0F, MOTION_OVERLAY_MAX_OPACITY)
val tint = if (player.isUnderWater && currentBehaviourKey == DolphinBehaviour.KEY) BiomeColors.getAverageWaterColor(minecraft.level as BlockAndTintGetter, riddenEntity.blockPosition()) else 0xFFFFFF
motionFrameIntervals += updateInterval * (if (minecraft.options.cameraType.isMirrored) -1 else 1)
val frameIndex = floor(motionFrameIntervals).toInt() % MOTION_FRAMES
blitk(
matrixStack = context.pose(),
texture = motionLinesResource,
x = 0,
y = 0,
textureHeight = 2560,
width = minecraft.window.guiScaledWidth,
height = minecraft.window.guiScaledHeight,
vOffset = 256 * frameIndex,
alpha = opacity,
red = FastColor.ARGB32.red(tint) / 255F,
green = FastColor.ARGB32.green(tint) / 255F,
blue = FastColor.ARGB32.blue(tint) / 255F
)
} else if (motionFadeFrames > 0) {
motionFadeFrames = 0
}
}
// Don't render if duration config set to 0 or less
if (controlsMaxDurationFrames <= 0F) return
private fun setCurrentRideBehaviour(ridingBehaviourSettings: RidingBehaviourSettings, ridingBehaviourState: RidingBehaviourState) {
val rideBehaviourKey = ridingBehaviourSettings.key
val rideBehaviourSettings = riddenEntity.ridingController?.context?.settings ?: return
val ridingBehaviourState = riddenEntity.ridingController?.context?.state ?: return
val rideBehaviourKey = rideBehaviourSettings.key
// Update current ride behaviour if changed
// If composite, get active behaviour instead
// Update current ride behaviour if changed.
// If behaviour is composite, get active behaviour instead
if (rideBehaviourKey == CompositeBehaviour.KEY) {
val activeBehaviour = (ridingBehaviourState as CompositeState).activeBehaviour.get()
if (currentBehaviourKey != activeBehaviour) {
@@ -128,12 +174,21 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
currentBehaviourKey = rideBehaviourKey
resetControlsOverlayState()
}
}
private fun renderRideControls(minecraft: Minecraft, context: GuiGraphics, updateInterval: Float, ridingBehaviourSettings: RidingBehaviourSettings, ridingBehaviourState: RidingBehaviourState) {
// Update max duration if user has changed config
val configDuration = Cobblemon.config.displayControlSeconds * BASELINE_FPS
if (controlsMaxDurationFrames != configDuration) {
controlsMaxDurationFrames = configDuration
resetControlsOverlayState()
}
// Don't render if duration config set to 0 or less
if (controlsMaxDurationFrames <= 0F) return
// Render elements if entity has ride behaviour and if display duration has not ended yet
if (rideBehaviourSettings != null && controlsFadeFrames > 0) {
val tickDelta = tickCounter.realtimeDeltaTicks.takeIf { !minecraft.isPaused } ?: 0F
val updateInterval = (tickDelta / 20F) * BASELINE_FPS
if (ridingBehaviourSettings != null && controlsFadeFrames > 0) {
controlsDurationFrames = max(controlsDurationFrames - updateInterval, 0F)
if (controlsDurationFrames == 0F && controlsFadeFrames > 0) controlsFadeFrames = max(controlsFadeFrames - updateInterval, 0F)
@@ -1,153 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui
import com.cobblemon.mod.common.api.gui.blitk
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.AbstractWidget
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.gui.narration.NarrationElementOutput
import net.minecraft.network.chat.CommonComponents
import net.minecraft.resources.ResourceLocation
import kotlin.math.floor
open class VariableObjectSelectionList(x: Int, y: Int, width: Int, height: Int): AbstractWidget(x, y, width, height, CommonComponents.EMPTY) {
val children = mutableListOf<Entry>()
var listHeight = 0
var scrollAmount = 0.0
fun updateScroll(offset: Double) {
setScroll(scrollAmount + offset)
}
fun getMaxScroll(): Int {
return (listHeight - height).coerceAtLeast(0)
}
fun setScroll(scroll: Double) {
scrollAmount = scroll.coerceIn(0.0, getMaxScroll().toDouble())
}
fun removeEntry(index: Int) {
listHeight -= children[index].height
children.removeAt(index)
updatePositions()
}
fun removeEntry(entry: Entry) {
listHeight -= entry.height
children.remove(entry)
updatePositions()
}
fun removeLastEntry() {
listHeight -= children.last().height
children.removeLast()
}
fun updatePositions() {
var stackHeight = 0
children.forEach {
it.scrolledY = stackHeight
stackHeight += it.height
}
updateScroll(0.0)
}
fun addEntry(entry: Entry) {
children.add(entry)
entry.scrolledY = listHeight
listHeight += entry.height
}
override fun renderWidget(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
var stackHeight = -scrollAmount.toInt()
guiGraphics.enableScissor(x, y, x + width, y + height)
children.forEachIndexed { index, entry ->
if (stackHeight in 1..<height || stackHeight + entry.height in 1..<height) {
entry.render(guiGraphics, index, x, y + stackHeight, mouseX, mouseY, partialTick)
}
stackHeight += entry.height
}
guiGraphics.disableScissor()
}
fun getEntryAtPosition(mouseX: Int, mouseY: Int): Entry? {
if (mouseX in x..(x + width) && mouseY in y..(y + height)) {
var stackHeight = -scrollAmount
children.forEach {
if (mouseY.toDouble() in (y + stackHeight)..(y + stackHeight + it.height)) {
return it
}
stackHeight += it.height
}
}
return null
}
fun ensureVisible(index: Int) {
val entry = children[index]
if (entry.scrolledY - scrollAmount < 0) {
setScroll(entry.scrolledY.toDouble())
} else if (entry.scrolledY + entry.height > height) {
setScroll(entry.scrolledY.toDouble() + entry.height)
}
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, horizontalAmount: Double, verticalAmount: Double): Boolean {
updateScroll(-verticalAmount * (listHeight / children.size / 2))
return true
}
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
val entry = getEntryAtPosition(pMouseX.toInt(), pMouseY.toInt())
if (entry != null) {
return entry.mouseClicked(pMouseX, pMouseY, pButton)
}
return false
}
override fun mouseReleased(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
return children.any {
it.mouseReleased(pMouseX, pMouseY, pButton)
} || super.mouseReleased(pMouseX, pMouseY, pButton)
}
fun getRowTop(entry: Entry): Int {
var stackHeight = -scrollAmount.toInt()
children.forEach {
if (it == entry) {
return y + stackHeight
}
stackHeight += it.height
}
return y
}
override fun defaultButtonNarrationText(pNarrationElementOutput: NarrationElementOutput) {}
override fun updateWidgetNarration(narrationElementOutput: NarrationElementOutput) {}
abstract inner class Entry(var height: Int): GuiEventListener {
var scrolledY: Int = 0
private var widgetFocused = false
override fun setFocused(focused: Boolean) {
this.widgetFocused = focused
}
override fun isFocused(): Boolean = widgetFocused
abstract fun render(guiGraphics: GuiGraphics, index: Int, x: Int, y: Int, mouseX: Int, mouseY: Int, partialTick: Float)
}
inner class EmptySeparator(height: Int): Entry(height) {
override fun render(guiGraphics: GuiGraphics, index: Int, x: Int, y: Int, mouseX: Int, mouseY: Int, partialTick: Float) {}
}
}
@@ -1,100 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.AbstractWidget
import net.minecraft.client.gui.narration.NarrationElementOutput
import net.minecraft.client.sounds.SoundManager
import net.minecraft.network.chat.CommonComponents
import net.minecraft.resources.ResourceLocation
class VariableObjectSelectionScrollbar(var parent: VariableObjectSelectionList, x: Int, y: Int, width: Int, height: Int): AbstractWidget(x, y, width, height, CommonComponents.EMPTY) {
companion object {
private val scrollerResource: ResourceLocation = ResourceLocation("minecraft", "textures/gui/sprites/widget/scroller.png")
private val scrollerBackgroundResource: ResourceLocation = ResourceLocation("minecraft", "textures/gui/sprites/widget/scroller_background.png")
private const val SCROLLER_HEIGHT = 32
}
private var scrolling = false
private var scrollHoldOffset = 0.0
fun scrollbarVisible(): Boolean = parent.getMaxScroll() > 0
override fun renderWidget(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
if (scrollbarVisible()) {
val scrollPosition = (parent.scrollAmount / parent.getMaxScroll()) * (height - SCROLLER_HEIGHT)
blitk(
matrixStack = guiGraphics.pose(),
texture = scrollerBackgroundResource,
x = x,
y = y,
width = width,
height = height,
)
blitk(
matrixStack = guiGraphics.pose(),
texture = scrollerResource,
x = x,
y = y + scrollPosition,
width = width,
height = SCROLLER_HEIGHT,
textureWidth = 6,
textureHeight = SCROLLER_HEIGHT
)
}
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
return parent.mouseScrolled(mouseX, mouseY, scrollX, scrollY)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (mouseX.toInt() in x..(x + width) && mouseY.toInt() in y..(y + height)) {
if (button == 0) {
var scrollPosition = (parent.scrollAmount / parent.getMaxScroll()) * (height - SCROLLER_HEIGHT)
if (mouseY !in (y + scrollPosition)..(y + scrollPosition + SCROLLER_HEIGHT)) {
val scrollRatio =
((mouseY - y - SCROLLER_HEIGHT / 2) / (height - SCROLLER_HEIGHT)).coerceIn(0.0, 1.0)
parent.setScroll(scrollRatio * parent.getMaxScroll())
scrollPosition = (parent.scrollAmount / parent.getMaxScroll()) * (height - SCROLLER_HEIGHT)
}
scrollHoldOffset = mouseY - y - scrollPosition
scrolling = true
return true
}
}
return false
}
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, dragX: Double, dragY: Double): Boolean {
if (button == 0 && scrolling) {
val scrollRatio = ((mouseY - y - scrollHoldOffset) / (height - SCROLLER_HEIGHT)).coerceIn(0.0,1.0)
parent.setScroll(scrollRatio * parent.getMaxScroll())
return true
}
return false
}
override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (button == 0 && scrolling) {
scrolling = false
return true
}
return false
}
override fun playDownSound(handler: SoundManager) {}
override fun updateWidgetNarration(narrationElementOutput: NarrationElementOutput) {}
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.client.gui.battle.subscreen
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.battles.FleeAttemptActionResponse
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.SingleActionRequest
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
@@ -66,7 +65,7 @@ class BattleGeneralActionSelection(
addOption(rank++, battleLang("ui.run"), BattleGUI.runResource) {
CobblemonClient.battle?.minimised = true
battleGUI.selectAction(request, FleeAttemptActionResponse())
Minecraft.getInstance().player?.displayClientMessage(battleLang("run_prompt"), false)
playDownSound(Minecraft.getInstance().soundManager)
}
} else {
@@ -375,8 +375,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
matrixStack = matrices,
partialTicks = delta,
rotation = Quaternionf().fromEulerXYZDegrees(rotationVector),
state = state,
blockLight = 15
state = state
)
matrices.popPose()
@@ -15,19 +15,18 @@ import com.cobblemon.mod.common.api.gui.ColourLibrary
import com.cobblemon.mod.common.api.gui.MultiLineLabelK
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.ExitButton
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.gui.VariableObjectSelectionScrollbar
import com.cobblemon.mod.common.client.gui.startselection.widgets.CategoryList
import com.cobblemon.mod.common.client.gui.startselection.widgets.SelectionButton
import com.cobblemon.mod.common.client.gui.startselection.widgets.ExitButton
import com.cobblemon.mod.common.client.gui.startselection.widgets.preview.ArrowButton
import com.cobblemon.mod.common.client.gui.startselection.widgets.preview.SelectionButton
import com.cobblemon.mod.common.client.gui.startselection.widgets.preview.StarterRoundabout
import com.cobblemon.mod.common.client.gui.summary.Summary.Companion.PARTY
import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.type.DualTypeWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.type.SingleTypeWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.type.TypeWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.config.starter.RenderableStarterCategory
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
@@ -35,14 +34,13 @@ import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.math.toRGB
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.toasts.Toast
import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.resources.ResourceLocation
import net.minecraft.sounds.SoundEvent
import java.io.FileNotFoundException
import net.minecraft.network.chat.Component
/**
* Starterselection Screen Thingy
@@ -51,31 +49,32 @@ import java.io.FileNotFoundException
* @since 2022-06-18
*/
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()), CobblemonRenderable {
companion object {
// Size of UI at scale 1
private const val BASE_WIDTH = 239
private const val BASE_HEIGHT = 197
private const val BASE_WIDTH = 200
private const val BASE_HEIGHT = 175
// Resources
private val baseResource = cobblemonResource("textures/gui/starterselection/base.png")
private val backgroundResource = cobblemonResource("textures/gui/starterselection/background.png")
private val backgroundBallResource = cobblemonResource("textures/gui/starterselection/background_poke_ball.png")
private val base = cobblemonResource("textures/gui/starterselection/starterselection_base.png")
private val baseUnderlay = cobblemonResource("textures/gui/starterselection/starterselection_base_underlay.png")
private val baseFrame = cobblemonResource("textures/gui/starterselection/starterselection_base_frame.png")
private val platformResource = cobblemonResource("textures/gui/starterselection/platform_base.png")
private val platformShadow = cobblemonResource("textures/gui/pokedex/platform_shadow.png")
private val typeSpacerResource = cobblemonResource("textures/gui/starterselection/type_spacer_single.png")
private val ballResource = cobblemonResource("textures/item/poke_balls/poke_ball.png")
// Type Backgrounds
private val singleTypeBackground = cobblemonResource("textures/gui/starterselection/starterselection_type_slot1.png")
private val doubleTypeBackground = cobblemonResource("textures/gui/starterselection/starterselection_type_slot2.png")
}
var currentSelection = 0
lateinit var currentCategory: RenderableStarterCategory
private var currentSelection = 0
private lateinit var currentCategory: RenderableStarterCategory
private lateinit var modelWidget: ModelWidget
private lateinit var currentPokemon: RenderablePokemon
private lateinit var typeWidget: TypeWidget
private lateinit var starterRoundaboutCenter: StarterRoundabout
private lateinit var starterRoundaboutLeft: StarterRoundabout
private lateinit var starterRoundaboutRight: StarterRoundabout
var ticksElapsed = 0
var currentBallBackgroundFrame = 0
override fun renderBlurredBackground(delta: Float) {}
override fun renderBlurredBackground(delta: Float) { }
override fun renderMenuBackground(context: GuiGraphics) {}
@@ -96,24 +95,55 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
return
}
addRenderableWidget(
CategoryList(
paneWidth = 71, paneHeight = BASE_HEIGHT - 11,
topOffset = 6,
entryHeight = 20, entryWidth = 57,
categories = categories,
listX = x - 2, listY = y + 8,
starterSelectionScreen = this
)
)
val rightButton = ArrowButton(
pX = x + 183, pY = y + 151,
pWidth = 9, pHeight = 14,
right = true
) {
right()
}
val leftButton = ArrowButton(
pX = x + 72, pY = y + 151,
pWidth = 9, pHeight = 14,
right = false
) {
left()
}
addRenderableWidget(rightButton)
addRenderableWidget(leftButton)
currentCategory = categories.first()
currentPokemon = currentCategory.pokemon[currentSelection]
with(currentPokemon) {
modelWidget = ModelWidget(
pX = x + 6, pY = y + 17,
pWidth = 118, pHeight = 100,
pX = x + 85, pY = y + 50,
pWidth = 102, pHeight = 100,
pokemon = this,
baseScale = 2.7f,
baseScale = 2.0f,
playCryOnClick = true,
offsetY = -12.0
)
typeWidget = typeWidget(this, x, y)
}
addRenderableWidget(modelWidget)
val selectionButton = SelectionButton(
pX = x + 13, pY = y + 180,
pX = x + 106, pY = y + 124,
pWidth = SelectionButton.BUTTON_WIDTH, pHeight = SelectionButton.BUTTON_HEIGHT
) {
CobblemonNetwork.sendToServer(
@@ -122,214 +152,182 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
selected = currentSelection
)
)
playSound(CobblemonSounds.GUI_CLICK)
onClose()
Minecraft.getInstance().setScreen(null)
}
addRenderableWidget(selectionButton)
// Add Exit Button
starterRoundaboutCenter = StarterRoundabout(
pX = x + 119, pY = height / 2 + 84,
pWidth = StarterRoundabout.MODEL_WIDTH, pHeight = StarterRoundabout.MODEL_HEIGHT,
pokemon = currentPokemon,
rotationVector = this.modelWidget.rotationVector
)
starterRoundaboutLeft = StarterRoundabout(
pX = x + 89, pY = height / 2 + 84,
pWidth = StarterRoundabout.MODEL_WIDTH, pHeight = StarterRoundabout.MODEL_HEIGHT,
pokemon = currentCategory.pokemon[leftOfCurrentSelection()],
clickAction = { _, _ -> this.left() },
rotationVector = this.modelWidget.rotationVector
)
starterRoundaboutRight = StarterRoundabout(
pX = x + 149, pY = height / 2 + 84,
pWidth = StarterRoundabout.MODEL_WIDTH, pHeight = StarterRoundabout.MODEL_HEIGHT,
pokemon = currentCategory.pokemon[rightOfCurrentSelection()],
clickAction = { _, _ -> this.right() },
rotationVector = this.modelWidget.rotationVector
)
addRenderableWidget(starterRoundaboutLeft)
addRenderableWidget(starterRoundaboutCenter)
addRenderableWidget(starterRoundaboutRight)
addRenderableWidget(
ExitButton(pX = x + 210, pY = y + 181) {
playSound(CobblemonSounds.GUI_CLICK)
onClose()
ExitButton(
pX = x + 181, pY = y + 2,
pWidth = 16, pHeight = 12,
pXTexStart = 0, pYTexStart = 0, pYDiffText = 0
) {
Minecraft.getInstance().setScreen(null)
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
}
)
val categoryList = CategoryList(
paneWidth = 97, paneHeight = 145,
categories = categories,
listX = x + 134, listY = y + 27,
starterSelectionScreen = this
)
addRenderableWidget(categoryList)
addRenderableWidget(VariableObjectSelectionScrollbar(
parent = categoryList,
x = x + 231,
y = y + 27,
width = 3,
height = 145
))
}
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
val matrices = context.pose()
val x = (width - BASE_WIDTH) / 2
val y = (height - BASE_HEIGHT) / 2
//Background
// Render Underlay
blitk(
matrixStack = matrices,
texture = backgroundResource,
x = x + 6,
y = y + 17,
width = 118,
height = 100
texture = baseUnderlay,
x = x, y = y,
width = BASE_WIDTH, height = BASE_HEIGHT
)
// Render Base
blitk(
matrixStack = matrices,
texture = backgroundBallResource,
x = x + 10.5,
y = y + 12.5,
width = 109,
height = 109,
textureHeight = 1744,
vOffset = currentBallBackgroundFrame * 109
texture = base,
x = x, y = y,
width = BASE_WIDTH, height = BASE_HEIGHT
)
//Platform
// Render Frame
val (r, g, b) = currentPokemon.form.primaryType.hue.toRGB()
blitk(
matrixStack = matrices,
texture = platformResource,
x = x + 8.5,
y = y + 88,
width = 113,
height = 32
texture = baseFrame,
red = r,
green = g,
blue = b,
x = x, y = y,
width = BASE_WIDTH, height = BASE_HEIGHT
)
val typePlatform = getPlatformResource(currentPokemon.form.primaryType)
if (typePlatform != null) {
blitk(
matrixStack = matrices,
texture = typePlatform,
x = x + 8.5,
y = y + 82,
width = 113,
height = 30
)
}
blitk(
matrixStack = matrices,
texture = platformShadow,
x = (x + 43) / 0.5F,
y = (y + 93.5) / 0.5F,
width = 90,
height = 20,
scale = 0.5F
)
//Base
blitk(
matrixStack = matrices,
texture = baseResource,
x = x,
y = y,
width = BASE_WIDTH,
height = BASE_HEIGHT
)
//Type Icon
TypeIcon(
x = x + 65,
y = y + 120,
type = currentPokemon.form.primaryType,
secondaryType = currentPokemon.form.secondaryType,
centeredX = true
).render(context)
if (currentPokemon.form.secondaryType == null) {
blitk(
matrixStack = matrices,
texture = typeSpacerResource,
x = x + 47,
y = y + 123,
width = 36,
height = 12
)
}
//Name
blitk(
matrixStack = matrices,
texture = ballResource,
x = (x + 4) / 0.5F,
y = (y + 3) / 0.5F,
width = 16,
height = 16,
scale = 0.5F
)
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = currentPokemon.species.translatedName.bold(),
x = x + 14,
y = y + 2,
shadow = true
)
// Pokédex Number
// Add preceding zeroes if Pokédex number is less than 4 digits
var dexNo = currentPokemon.species.nationalPokedexNumber.toString()
while (dexNo.length < 4) {
dexNo = "0$dexNo"
}
dexNo = "#$dexNo"
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = dexNo.text().bold(),
x = x + 79,
y = y + 1,
shadow = true
)
//"Title"
// Render Text
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = lang("ui.starter.title").bold(),
x = x + 172,
y = y + 11,
shadow = true,
centered = true
x = x + 125, y = y + 3F,
centered = true,
scale = 1.4F,
maxCharacterWidth = 120,
shadow = true
)
//Description Text
val smallTextScale = 0.5F
// Render Name
val pokemonName = currentPokemon.species.translatedName
val scale = 0.8F
drawScaledText(
context = context,
text = pokemonName,
centered = true,
scale = scale,
maxCharacterWidth = 50,
x = x + 94,
y = y + 19.5,
shadow = false
)
// Render Description
val scale2 = 0.60F
matrices.pushPose()
matrices.scale(smallTextScale, smallTextScale, 1F)
matrices.scale(scale2, scale2, 1F)
// TODO use all pokedex lines across multiple clickable pages in this screen
MultiLineLabelK.create(
component = currentPokemon.form.pokedex.first().asTranslated(),
width = 114 / smallTextScale,
maxLines = 5
width = 127,
maxLines = 4
).renderLeftAligned(
context = context,
x = (x + 8) / smallTextScale,
y = (y + 143) / smallTextScale,
ySpacing = 5.5 / smallTextScale,
colour = ColourLibrary.WHITE,
shadow = true
x = (x + 119) / scale2 + 4, y = (y + 18) / scale2 + 4.0,
ySpacing = (8.0 / scale2) - 1.25,
colour = ColourLibrary.WHITE, shadow = false
)
matrices.popPose()
// Render the type background
blitk(
matrixStack = matrices,
texture = currentPokemon.form.secondaryType?.let { doubleTypeBackground } ?: singleTypeBackground,
x = (currentPokemon.form.secondaryType?.let { x + 76.75 } ?: (x + 85.25)), y = y + 29.4,
width = currentPokemon.form.secondaryType?.let { 35.25 } ?: 19, height = 19.25
)
// Render the type widget
typeWidget.render(context, mouseX, mouseY, delta)
// Render the rest
super.render(context, mouseX, mouseY, delta)
}
fun getPlatformResource(type: ElementalType): ResourceLocation? {
return try {
cobblemonResource("textures/gui/starterselection/starter_platform_base_${type.showdownId}.png")
} catch (error: FileNotFoundException) {
null
}
fun changeCategory(category: RenderableStarterCategory) {
currentCategory = category
currentSelection = 0
updateSelection()
}
fun selectPokemon(category: RenderableStarterCategory, slot: Int) {
currentCategory = category
currentSelection = slot
private fun right() {
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
currentSelection = rightOfCurrentSelection()
updateSelection()
}
private fun rightOfCurrentSelection() : Int = if (currentSelection + 1 <= currentCategory.pokemon.size - 1) currentSelection + 1 else 0
private fun left() {
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
currentSelection = leftOfCurrentSelection()
updateSelection()
}
private fun leftOfCurrentSelection() : Int = if (currentSelection - 1 == -1) currentCategory.pokemon.size - 1 else currentSelection - 1
private fun updateSelection() {
currentPokemon = currentCategory.pokemon[currentSelection].also {
modelWidget.pokemon = it
typeWidget = typeWidget(it, (width - BASE_WIDTH) / 2, (height - BASE_HEIGHT) / 2)
}
starterRoundaboutLeft.pokemon = currentCategory.pokemon[leftOfCurrentSelection()]
starterRoundaboutCenter.pokemon = currentPokemon
starterRoundaboutRight.pokemon = currentCategory.pokemon[rightOfCurrentSelection()]
}
override fun tick() {
ticksElapsed++
val delay = 3
if (ticksElapsed % delay == 0) currentBallBackgroundFrame++
if (currentBallBackgroundFrame == 16) currentBallBackgroundFrame = 0
private fun typeWidget(pokemon: RenderablePokemon, x: Int, y: Int) : TypeWidget {
return pokemon.form.secondaryType?.let {
DualTypeWidget(
pX = x + 77, pY = y + 30,
pWidth = 18, pHeight = 18,
pMessage = Component.literal("What?"),
mainType = pokemon.form.primaryType, secondaryType = it
)
} ?: SingleTypeWidget(
pX = x + 85, pY = y + 30,
pWidth = 18, pHeight = 18,
type = pokemon.form.primaryType,
renderText = false
)
}
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
@@ -342,8 +340,4 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
}
override fun isPauseScreen() = true
fun playSound(soundEvent: SoundEvent) {
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1.0F))
}
}
@@ -8,212 +8,126 @@
package com.cobblemon.mod.common.client.gui.startselection.widgets
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.PokemonGUIAnimationStyle
import com.cobblemon.mod.common.client.gui.VariableObjectSelectionList
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.startselection.StarterSelectionScreen
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.config.starter.RenderableStarterCategory
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.ObjectSelectionList
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import org.joml.Quaternionf
import org.joml.Vector3f
import net.minecraft.network.chat.Component
class CategoryList(
private val paneWidth: Int,
private val paneHeight: Int,
topOffset: Int,
private val entryWidth: Int,
entryHeight: Int,
private val categories: List<RenderableStarterCategory>,
val listX: Int,
val listY: Int,
private val minecraft: Minecraft = Minecraft.getInstance(),
private val starterSelectionScreen: StarterSelectionScreen
) : VariableObjectSelectionList(
listX,
listY,
) : ObjectSelectionList<CategoryList.Category>(
minecraft,
paneWidth,
paneHeight
paneHeight,
topOffset,
entryHeight
), CobblemonRenderable {
companion object {
private val headerResource = cobblemonResource("textures/gui/starterselection/selection_container_header.png")
private val footerResource = cobblemonResource("textures/gui/starterselection/selection_container_footer.png")
private val edgeResource = cobblemonResource("textures/gui/starterselection/selection_container_edge.png")
private val containerResource = cobblemonResource("textures/gui/starterselection/selection_container.png")
private val buttonResource = cobblemonResource("textures/gui/starterselection/starter_selection.png")
private val buttonActiveResource = cobblemonResource("textures/gui/starterselection/starter_selection_active.png")
const val MARGIN = 4
const val HEADER_HEIGHT = 7
const val BUTTON_SEPERATION = 3
const val CONTAINER_BUTTON_SIZE = 25
const val CONTAINER_WIDTH = 89
private const val CATEGORY_BUTTON_WIDTH = 51.5f
private const val CATEGORY_BUTTON_HEIGHT = 16f
private const val ENTRY_X_OFFSET = 10f
private val categoryResource = cobblemonResource("textures/gui/starterselection/starterselection_slot.png")
}
init {
addEntry(EmptySeparator(MARGIN))
createEntries().forEach {
addEntry(it)
addEntry(EmptySeparator(MARGIN))
}
this.x = listX
this.y = listY
this.correctSize()
createEntries().forEach { addEntry(it) }
//this.setRenderBackground(false)
}
private fun createEntries() = categories.map { category ->
val rows = (category.pokemon.size - 1) / 3 + 1
val height = CONTAINER_BUTTON_SIZE * rows + BUTTON_SEPERATION * (rows + 1) + HEADER_HEIGHT + 3
Category(category, height)
private fun createEntries() = categories.map {
Category(it)
}
inner class Category(private val category: RenderableStarterCategory, height: Int) : Entry(height) {
override fun renderListBackground(context: GuiGraphics) {}
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
super.renderWidget(context, mouseX, mouseY, delta)
correctSize()
}
private fun correctSize() {
this.setRectangle(this.paneWidth, this.paneHeight, this.listX, this.listY)
}
private fun scale(n: Int): Int = (this.minecraft.window.guiScale * n).toInt()
override fun getRowWidth() = this.entryWidth
override fun getScrollbarPosition(): Int {
return this.listX + this.width - 5
}
inner class Category(private val category: RenderableStarterCategory) : Entry<Category>() {
override fun render(
guiGraphics: GuiGraphics,
context: GuiGraphics,
index: Int,
x: Int,
y: Int,
x: Int,
entryWidth: Int,
entryHeight: Int,
mouseX: Int,
mouseY: Int,
partialTick: Float
hovered: Boolean,
tickDelta: Float
) {
val rows = (category.pokemon.size - 1) / 3 + 1
val matrices = guiGraphics.pose()
//Header
blitk(
matrixStack = matrices,
texture = headerResource,
x = x + MARGIN,
y = y,
width = CONTAINER_WIDTH,
height = HEADER_HEIGHT
)
val smallTextScale = 0.5F
drawScaledText(
context = guiGraphics,
text = category.displayNameText.bold(),
x = x + MARGIN + CONTAINER_WIDTH / 2,
y = y + 2,
shadow = true,
centered = true,
scale = smallTextScale
)
//Container
var stackHeight = HEADER_HEIGHT
blitk(
matrixStack = matrices,
texture = edgeResource,
x = x + MARGIN,
y = y + stackHeight,
width = CONTAINER_WIDTH,
height = 1
)
stackHeight += 1
val containerInnerHeight = CONTAINER_BUTTON_SIZE * rows + BUTTON_SEPERATION * (rows + 1)
blitk(
matrixStack = matrices,
texture = containerResource,
x = x + MARGIN,
y = y + stackHeight,
width = CONTAINER_WIDTH,
height = containerInnerHeight
)
stackHeight += containerInnerHeight
blitk(
matrixStack = matrices,
texture = edgeResource,
x = x + MARGIN,
y = y + stackHeight,
width = CONTAINER_WIDTH,
height = 1
)
stackHeight += 1
//Footer
blitk(
matrixStack = matrices,
texture = footerResource,
x = x + MARGIN,
y = y + stackHeight,
width = CONTAINER_WIDTH,
height = 1
)
//Buttons
for (index in 0..<category.pokemon.size) {
val row = index / 3
val column = index % 3
val startX = x + MARGIN + 5 + column * (CONTAINER_BUTTON_SIZE + 2)
val startY = y + HEADER_HEIGHT + 1 + BUTTON_SEPERATION + row * (BUTTON_SEPERATION + CONTAINER_BUTTON_SIZE)
val active = starterSelectionScreen.currentCategory == category && starterSelectionScreen.currentSelection == index
val hovered = getEntryAtPosition(mouseX, mouseY) == this && mouseX in startX..(startX + CONTAINER_BUTTON_SIZE) && mouseY in startY..(startY + CONTAINER_BUTTON_SIZE)
val matrices = context.pose()
val isHovered = mouseX >= x && mouseY >= y && mouseX < x + entryWidth && mouseY < y + (entryHeight - 1)
if (isHovered) {
blitk(
matrixStack = matrices,
texture = if (active) buttonActiveResource else buttonResource,
x = startX,
y = startY,
width = CONTAINER_BUTTON_SIZE,
height = CONTAINER_BUTTON_SIZE,
textureHeight = CONTAINER_BUTTON_SIZE * 2,
vOffset = if (hovered) CONTAINER_BUTTON_SIZE else 0
x = x + 2.5f, y = y,
texture = categoryResource,
width = CATEGORY_BUTTON_WIDTH, height = CATEGORY_BUTTON_HEIGHT,
red = 0.75f, green = 0.75f, blue = 0.75f
)
matrices.pushPose()
matrices.translate(startX + (CONTAINER_BUTTON_SIZE / 2.0), startY.toDouble() - 6, 0.0)
matrices.scale(3.5F, 3.5F, 1F)
val state = FloatingState()
drawProfilePokemon(
species = category.pokemon[index].species.resourceIdentifier,
} else
blitk(
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = state,
scale = 4.5F,
partialTicks = 0F
x = x + 2.5f, y = y,
texture = categoryResource,
width = CATEGORY_BUTTON_WIDTH, height = CATEGORY_BUTTON_HEIGHT
)
matrices.popPose()
}
drawScaledText(
context = context,
text = category.displayNameText,
x = x + 28,
y = y + 4.5F,
scale = 1F,
maxCharacterWidth = 50,
shadow = true,
centered = true
)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
val entryY = getRowTop(this)
val hoveredButton = getButtonHovered(x, entryY, mouseX, mouseY)
if (hoveredButton != -1) {
starterSelectionScreen.selectPokemon(category, hoveredButton)
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
return true
}
return false
starterSelectionScreen.changeCategory(category = category)
minecraft.soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
return true
}
private fun getButtonHovered(x: Int, y: Int, mouseX: Double, mouseY: Double): Int {
for (index in 0..<category.pokemon.size) {
val row = index / 3
val column = index % 3
val startX = x + MARGIN + 5 + column * (CONTAINER_BUTTON_SIZE + 2)
val startY = y + HEADER_HEIGHT + 1 + BUTTON_SEPERATION + row * (BUTTON_SEPERATION + CONTAINER_BUTTON_SIZE)
if (getEntryAtPosition(mouseX.toInt(), mouseY.toInt()) == this && mouseX.toInt() in startX..(startX + CONTAINER_BUTTON_SIZE) && mouseY.toInt() in startY..(startY + CONTAINER_BUTTON_SIZE)) {
return index
}
}
return -1
override fun getNarration(): Component {
return Component.literal("Yes")
}
}
}
@@ -6,13 +6,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.startselection.widgets
package com.cobblemon.mod.common.client.gui.startselection.widgets.preview
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.ColourLibrary
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
@@ -28,39 +26,45 @@ class SelectionButton(
pX: Int, pY: Int,
pWidth: Int, pHeight: Int,
onPress: OnPress
): Button(pX, pY, pWidth, pHeight, Component.literal("SelectionButton"), onPress, DEFAULT_NARRATION),
CobblemonRenderable {
): Button(pX, pY, pWidth, pHeight, Component.literal("SelectionButton"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private val buttonResource = cobblemonResource("textures/gui/starterselection/choose_button.png")
const val BUTTON_WIDTH = 106
const val BUTTON_HEIGHT = 14
const val TEXT_HEIGHT = 10
private val buttonTexture = cobblemonResource("textures/gui/starterselection/starterselection_button.png")
const val BUTTON_WIDTH = 56
const val BUTTON_HEIGHT = 12
private const val SCALE = 0.7f
}
override fun playDownSound(soundManager: SoundManager) {}
override fun playDownSound(soundManager: SoundManager) {
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
}
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
val matrices = context.pose()
blitk(
matrixStack = matrices,
texture = buttonResource,
x = x,
y = y,
width = BUTTON_WIDTH,
height = BUTTON_HEIGHT,
textureHeight = BUTTON_HEIGHT * 2,
vOffset = if (isHovered) BUTTON_HEIGHT else 0
)
if (isHovered)
blitk(
matrixStack = matrices,
texture = buttonTexture,
x = x + 0.6, y = y + 0.6,
width = BUTTON_WIDTH - 0.25, height = BUTTON_HEIGHT - 0.25,
red = 0.75f, green = 0.75f, blue = 0.75f
)
else
blitk(
matrixStack = matrices,
texture = buttonTexture,
x = x + 0.6, y = y + 0.6,
width = BUTTON_WIDTH - 0.25, height = BUTTON_HEIGHT - 0.25
)
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = lang("ui.starter.choosebutton").bold(),
x = x + BUTTON_WIDTH / 2,
y = y + BUTTON_HEIGHT / 2 - TEXT_HEIGHT / 2,
shadow = true,
centered = true
text = lang("ui.starter.choosebutton"),
x = x + BUTTON_WIDTH / 2, y = y + BUTTON_HEIGHT / 2 - 2.4,
colour = ColourLibrary.WHITE,
centered = true,
maxCharacterWidth = 68,
scale = SCALE,
shadow = true
)
}
}
@@ -31,7 +31,6 @@ class ModelWidget(
var offsetY: Double = 0.0,
val playCryOnClick: Boolean = false,
val shouldFollowCursor: Boolean = false,
val blockLight: Int = 13
): SoundlessWidget(pX, pY, pWidth, pHeight, Component.literal("Summary - ModelWidget")) {
companion object {
@@ -116,7 +115,6 @@ class ModelWidget(
partialTicks = partialTicks,
headYaw = currentYawAndPitch.first,
headPitch = currentYawAndPitch.second,
blockLight = blockLight
)
heldItemRenderer.renderOnModel(
@@ -1,25 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.net.debug
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.client.render.debug.LineState
import com.cobblemon.mod.common.client.render.debug.SteerForceRenderer
import com.cobblemon.mod.common.net.messages.client.debug.ClientboundUpdateObsAvoidPacket
import net.minecraft.client.Minecraft
object S2CUpdateObsAvoidHandler : ClientNetworkPacketHandler<ClientboundUpdateObsAvoidPacket> {
override fun handle(packet: ClientboundUpdateObsAvoidPacket, client: Minecraft) {
client.executeIfPossible {
//ObjectAvoidanceRenderer.avoidanceLines[packet.entityId] = packet.lines
val lineState = SteerForceRenderer.lineStates.getOrPut(packet.entityId) { LineState() }
lineState.update(packet.lines)
}
}
}
@@ -309,7 +309,6 @@ class SnowstormParticle(
boundingBox = AABB.ofSize(Vec3(x, y, z), radius, radius, radius)
if (dx == 0.0 && dy == 0.0 && dz == 0.0) {
updatePosition()
expandBoundingBoxForCulling(radius)
return
}
@@ -367,16 +366,6 @@ class SnowstormParticle(
}
}
updatePosition()
expandBoundingBoxForCulling(radius)
}
private fun expandBoundingBoxForCulling(collisionRadius: Double) {
val visualSizeX = abs(runtime.resolveDouble(storm.effect.particle.sizeX))
val visualSizeY = abs(runtime.resolveDouble(storm.effect.particle.sizeY))
val visualExtent = maxOf(visualSizeX, visualSizeY)
if (visualExtent > collisionRadius) {
boundingBox = AABB.ofSize(Vec3(x, y, z), visualExtent, visualExtent, visualExtent)
}
}
fun updatePosition() {
@@ -290,14 +290,8 @@ class ModelLayer {
val emissive: Boolean = false
val translucent: Boolean = false
val translucent_cull: Boolean = false
val scrolling: ScrollingTextureSettings? = null
}
class ScrollingTextureSettings(
val speedU: Float = 0.01F,
val speedV: Float = 0.01F
)
enum class SpriteType {
PORTRAIT,
PROFILE
@@ -1,116 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.debug
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import net.minecraft.client.Camera
import net.minecraft.client.Minecraft
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.util.Mth
import net.minecraft.world.phys.Vec3
/**
* Data class currently used for storing line data for rendering in [SteerForceRenderer]
*
* @author Jackson
* @since September 18th, 2025
*/
data class EntityDebugLine(
val vector: Vec3, // Direction/magnitude in world space, relative to entity origin
val r: Float,
val g: Float,
val b: Float,
val a: Float,
) : Encodable {
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeVec3(vector)
buffer.writeFloat(r)
buffer.writeFloat(g)
buffer.writeFloat(b)
buffer.writeFloat(a)
}
companion object {
operator fun invoke(vector: Vec3, r: Float = 1f, g: Float = 1f, b: Float = 1f, a: Float = 1f): EntityDebugLine {
return EntityDebugLine(vector, r.coerceIn(0f,1f), g.coerceIn(0f,1f), b.coerceIn(0f,1f), a.coerceIn(0f,1f))
}
fun decode(buffer: RegistryFriendlyByteBuf): EntityDebugLine {
val vector = buffer.readVec3()
return EntityDebugLine(vector, buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readFloat())
}
}
}
class LineState {
/**
* The comparison of the previous and current lines relies on the order being consistent
*/
var previousLines: List<EntityDebugLine> = emptyList()
var currentLines: List<EntityDebugLine> = emptyList()
var lastReceivedLineTick: Long? = null
fun tick() {
previousLines = currentLines
}
fun update(newLines: List<EntityDebugLine>) {
lastReceivedLineTick = Minecraft.getInstance().level?.gameTime
currentLines = newLines
if (previousLines.isEmpty()) previousLines = newLines
}
// entityPos: interpolated world position of the entity this tick
fun draw(vc: VertexConsumer, pose: PoseStack.Pose, partialTick: Float, camera: Camera, entity: PokemonEntity, partialTicks: Float) {
previousLines.zip(currentLines).forEach { (prev, curr) ->
val iVec = prev.vector.lerp(curr.vector, partialTick.toDouble())
val iR = prev.r.lerp(curr.r, partialTick)
val iG = prev.g.lerp(curr.g, partialTick)
val iB = prev.b.lerp(curr.b, partialTick)
val iA = prev.a.lerp(curr.a, partialTick)
// Interpolated world position — same method used everywhere in the renderer
val worldStart = Vec3(
Mth.lerp(partialTicks.toDouble(), entity.xOld, entity.x),
Mth.lerp(partialTicks.toDouble(), entity.yOld, entity.y),
Mth.lerp(partialTicks.toDouble(), entity.zOld, entity.z)
)
val worldEnd = worldStart.add(iVec)
val relStart = worldStart.subtract(camera.position)
val relEnd = worldEnd.subtract(camera.position)
// Normal is the normalized direction of the segment
val dir = iVec.normalize()
val nx = dir.x.toFloat()
val ny = dir.y.toFloat()
val nz = dir.z.toFloat()
vc.addVertex(pose.pose(), relStart.x.toFloat(), relStart.y.toFloat(), relStart.z.toFloat())
.setColor(iR, iG, iB, iA)
.setNormal(pose, nx, ny, nz)
vc.addVertex(pose.pose(), relEnd.x.toFloat(), relEnd.y.toFloat(), relEnd.z.toFloat())
.setColor(iR, iG, iB, iA)
.setNormal(pose, nx, ny, nz)
}
}
fun reset() {
previousLines = emptyList()
currentLines = emptyList()
}
}
private fun Float.lerp(end: Float, t: Float): Float = this + (end - this) * t.coerceIn(0f, 1f)
@@ -1,58 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.debug
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.Camera
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
object SteerForceRenderer {
// Lines to render attached to the uuid of entities.
val lineStates = mutableMapOf<Int, LineState>()
fun registerTickHandler() {
// Advance line States
PlatformEvents.CLIENT_TICK_PRE.subscribe {
lineStates.forEach { uuid, lineState ->
lineState.tick()
}
}
}
fun render(poseStack: PoseStack, multiBufferSource: MultiBufferSource, partialTicks: Float, camera: Camera) {
val matrix = poseStack.last().pose()
val level = Minecraft.getInstance().level ?: return
val currTick = level.gameTime
val ticksUntilStale = 3
val keysToRemove = lineStates.keys.filter { entityId ->
val entity = level.getEntity(entityId) as? PokemonEntity
val lastRecTick = lineStates[entityId]?.lastReceivedLineTick
entity == null || (lastRecTick != null && (currTick - lastRecTick) > ticksUntilStale)
}
keysToRemove.forEach { lineStates.remove(it) }
// One buffer for all independent line segments
val lineBuffer = multiBufferSource.getBuffer(RenderType.lines())
lineStates.forEach { entityId, lineState ->
val entity = level.getEntity(entityId) as? PokemonEntity ?: return@forEach
lineState.draw(lineBuffer, poseStack.last(), partialTicks, camera, entity, partialTicks)
}
}
}
@@ -20,7 +20,6 @@ import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.AnimatedModelTextureSupplier
import com.cobblemon.mod.common.client.render.ModelLayer
import com.cobblemon.mod.common.client.render.ScrollingTextureSettings
import com.cobblemon.mod.common.client.render.models.blockbench.animation.*
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockActiveAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
@@ -49,7 +48,6 @@ import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.blaze3d.vertex.VertexFormat
import com.mojang.math.Axis
import net.minecraft.Util
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderStateShard
@@ -455,16 +453,15 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
val provider = bufferProvider
if (provider != null) {
for (layer in currentLayers) {
val texture = layer.texture?.invoke(currentState ?: FloatingState()) ?: continue
val scrolling = layer.scrolling
val renderLayer: RenderType = if (scrolling != null) {
getScrollingLayer(texture, scrolling)
} else if (layer.texture is AnimatedModelTextureSupplier && layer.texture.interpolation) {
val interpolatedTexture = layer.texture.interpolatedTexture(currentState ?: FloatingState()) ?: continue
makeLayer(DynamicStateShard(interpolatedTexture), layer.emissive, layer.translucent, layer.translucent_cull)
} else {
getLayer(texture, layer.emissive, layer.translucent, layer.translucent_cull)
var renderLayer : RenderType
if (layer.texture is AnimatedModelTextureSupplier && layer.texture.interpolation) {
//Handle Interpolation
val texture = layer.texture.interpolatedTexture(currentState ?: FloatingState()) ?: continue
renderLayer = makeLayer(DynamicStateShard(texture), layer.emissive, layer.translucent, layer.translucent_cull)
}
else {
val texture = layer.texture?.invoke(currentState ?: FloatingState()) ?: continue
renderLayer = getLayer(texture, layer.emissive, layer.translucent, layer.translucent_cull)
}
val consumer = provider.getBuffer(renderLayer)
val tint = layer.tint
@@ -503,7 +500,7 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
!emissive && translucent && translucentCull -> RenderStateShard.RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER
!emissive && translucent -> RenderStateShard.RENDERTYPE_ENTITY_TRANSLUCENT_SHADER
!emissive && !translucent -> RenderStateShard.RENDERTYPE_ENTITY_CUTOUT_SHADER
else -> RenderStateShard.RENDERTYPE_ENTITY_TRANSLUCENT_EMISSIVE_SHADER
else -> RenderStateShard.RENDERTYPE_ENTITY_TRANSLUCENT_EMISSIVE_SHADER // This one should be changed to maybe a custom shader? Translucent stuffs with things
}
)
.setTextureState(texture)
@@ -536,12 +533,6 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
}
}
fun getScrollingLayer(texture: ResourceLocation, scrolling: ScrollingTextureSettings): RenderType {
val gameTime = Util.getMillis().toFloat() / 1000f
val offsetU = (gameTime * scrolling.speedU) % 1.0f
val offsetV = (gameTime * scrolling.speedV) % 1.0f
return RenderType.breezeWind(texture, offsetU, offsetV)
}
/** Applies the given pose's [ModelPartTransformation]s to the model, if there is a matching pose. */
fun applyPose(state: PosableState, pose: Pose, intensity: Float) = pose.transformedParts.forEach { it.apply(state, intensity) }
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PitchTiltAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
@@ -199,7 +198,6 @@ class PidgeottoModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
transformTicks = 10,
quirks = arrayOf(blink, flyQuirk1, flyQuirk2),
animations = arrayOf(
PitchTiltAnimation(bone = getPart("body"), maxChangePerTick = 1F),
singleBoneLook(),
bedrock("pidgeotto", "air_fly")
)
@@ -146,12 +146,6 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Battles, lang = "experience_share_multiplier", SERVER)
var experienceShareMultiplier = .5
@CobblemonConfigField(Category.Battles, lang = "award_experience_to_fainted_pokemon", SERVER)
var awardExperienceToFaintedPokemon = false
@CobblemonConfigField(Category.Battles, lang = "award_experience_on_battle_loss", SERVER)
var awardExperienceOnBattleLoss = false
@CobblemonConfigField(Category.Battles, lang = "lucky_egg_multiplier", SERVER)
var luckyEggMultiplier = 1.5
@@ -253,7 +247,7 @@ class CobblemonConfig {
var pastureBlockUpdateTicks = 40
@CobblemonConfigField(Category.World, lang = "pasture_max_wander_distance", SERVER)
var pastureMaxWanderDistance = 32
var pastureMaxWanderDistance = 64
@CobblemonConfigField(Category.World, lang = "pasture_max_per_chunk", SERVER)
var pastureMaxPerChunk = 4F
@@ -126,14 +126,6 @@ class StarterConfig {
PokemonProperties.parse("Fuecoco level=10"),
PokemonProperties.parse("Quaxly level=10"),
)
),
StarterCategory(
name = "Special",
displayName = "cobblemon.starterselection.category.special",
pokemon = mutableListOf(
PokemonProperties.parse("Pikachu level=10"),
PokemonProperties.parse("Eevee level=10")
)
)
)
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.entity.ai
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.entity.OmniPathingEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.ai.OmniPathNodeMaker
import com.cobblemon.mod.common.util.deleteNode
import com.cobblemon.mod.common.util.getWaterAndLavaIn
@@ -34,7 +35,6 @@ import net.minecraft.world.phys.Vec3
import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.acos
import kotlin.math.max
/**
* A navigator designed to work with the [OmniPathNodeMaker], allowing a path that can cross land, water, and air
@@ -49,8 +49,6 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
var cachedCurrentNode: Node? = null
var currentNodeDistance = 0F
var segmentIndex: Int = 0
var pathFollowTarget: Vec3? = null
data class NavigationContext(
val onHit: (damage: DamageSource) -> Unit = {},
@@ -162,65 +160,6 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
}
doStuckDetection(vec3d)
// Gather the steer target from the segment pathing
// TODO: this shouldn't live here
val currentPath = path ?: return
if (!currentPath.isDone) {
segmentIndex = segmentIndex.coerceIn(0, max(currentPath.nodeCount - 2, 0))
pathFollowTarget = getPathSteerTarget(currentPath, mob)
}
}
/**
* Gets a steering target for the current path
* This video explains it well: https://www.youtube.com/watch?v=rlZYT-uvmGQ
* Uses Reynolds path following for velocity steered entities
*/
fun getPathSteerTarget(
path: Path,
mob: Mob
): Vec3 {
// If this is the final segment then just seek towards the end
if (segmentIndex >= path.nodeCount - 1) return path.getNode(path.nodeCount - 1).asVec3().add(0.5, 0.0, 0.5)
// Determine future position to use in steering calculations
val lookAheadDist = 1.0 //TODO: Scale to look ahead a certain amount of ticks probably
val futurePos = mob.position().add(mob.deltaMovement.normalize().scale(lookAheadDist))
// Gather the current segment points
var pointS1 = path.getNode(segmentIndex).asVec3().add(0.5, 0.0, 0.5) // Add the 0.5's to get the blockface center as blockpos is on a corner
var pointS2 = path.getNode(segmentIndex + 1).asVec3().add(0.5, 0.0, 0.5)
// Project the future point onto the current segment
var vecA = futurePos.subtract(pointS1)
var vecB = pointS2.subtract(pointS1)
var normB = vecB.normalize()
val lenB = vecB.length()
var projAB = max(vecA.dot(normB), 0.0) // make at least 0 as negative means we are projecting behind the segment which we don't want
// If the projection goes off the front of the segment then advance to the next segment and recalculate the projection
if (projAB > lenB && segmentIndex < path.nodeCount - 2) {
segmentIndex++
pointS1 = path.getNode(segmentIndex).asVec3().add(0.5, 0.0, 0.5)
pointS2 = path.getNode(segmentIndex + 1).asVec3().add(0.5, 0.0, 0.5)
vecA = futurePos.subtract(pointS1)
vecB = pointS2.subtract(pointS1)
normB = vecB.normalize()
projAB = max(vecA.dot(normB), 0.0)
}
// Get the projected point on the segment
val projPoint = pointS1.add(normB.scale(projAB ))
// Determine if the future position is too far from the path by getting its distance from its projected position on the current path segment
val futureDistFromPath = projPoint.distanceTo(futurePos)
val acceptableDist = mob.bbWidth / 3.0 //TODO: figure out what this really needs to be
val pushForward = 0.1 // Advance the projected point along the segment to avoid going backwards
val seekPoint = if (futureDistFromPath < acceptableDist) futurePos.add(normB.scale(pushForward)) else projPoint.add(normB.scale(pushForward))
return seekPoint
}
fun isAirborne(world: Level, pos: BlockPos) =
@@ -284,8 +223,6 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
fun moveTo(x: Double, y: Double, z: Double, speed: Double = 1.0, navigationContext: NavigationContext) {
this.navigationContext = navigationContext
segmentIndex = 0
pathFollowTarget = null
this.moveTo(x, y, z, speed)
}
@@ -340,8 +277,6 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
}
override fun moveTo(path: Path?, speed: Double): Boolean {
segmentIndex = 0
pathFollowTarget = null
if (path != null && path.nodeCount > 0) {
val node = path.getNode(0)!!
// pokemonEntity.discard()
@@ -464,8 +399,6 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
this.cachedCurrentNode = null
path = null
nodeEvaluator.done()
segmentIndex = 0
pathFollowTarget = null
// In case a path is cancelled instead of completed, check if we should stop flying
if (pather.couldStopFlying() && !isAirborne(entity.level(), entity.blockPosition())) {
pather.setFlying(false)
@@ -1,77 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.entity.ai.steering
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToTrackingPlayers
import com.cobblemon.mod.common.client.render.debug.EntityDebugLine
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.debug.ClientboundUpdateObsAvoidPacket
import net.minecraft.world.phys.Vec3
// Runs a list of SteerRules in priority order, consuming a force budget.
// High priority rules get their full contribution first. Lower priority
// rules only get what budget remains.
class SteerArbitrator(
val entity: PokemonEntity,
val maxForce: Double,
val rules: MutableList<SteerRule> = mutableListOf()
) {
private var sortedRules: List<SteerRule> = emptyList()
private var dirty = true
fun addRule(rule: SteerRule) { rules.add(rule); dirty = true }
fun removeRule(rule: SteerRule) { rules.remove(rule); dirty = true }
fun clearRules() { rules.clear(); dirty = true }
fun calculate(debug: Boolean = false): Vec3 {
if (dirty) {
sortedRules = rules.sortedByDescending { it.priority }
dirty = false
}
var remaining = maxForce
var result = Vec3.ZERO
val debugLines = if (debug) mutableListOf<EntityDebugLine>() else null
for (rule in sortedRules) {
if (remaining <= 0.0) break
val force = rule.calculate() ?: continue
val scaled = force.scale(rule.weight.toDouble())
val len = scaled.length()
if (len <= 0.0) continue
val contribution = if (len <= remaining) {
remaining -= len
scaled
} else {
val partial = remaining
remaining = 0.0
scaled.normalize().scale(partial)
}
result = result.add(contribution)
debugLines?.let {
val (r, g, b) = rule.debugColor
it.add(EntityDebugLine(contribution.scale(50.0), r, g, b, 1.0f))
}
}
debugLines?.let {
if (result.lengthSqr() > 0.0)
it.add(EntityDebugLine(result.scale(50.0), 1f, 1f, 1f, 1.5f))
if (it.isNotEmpty())
sendPacketToTrackingPlayers(entity, ClientboundUpdateObsAvoidPacket(entity.id, it))
}
return result
}
}
@@ -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.entity.ai.steering
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.world.phys.Vec3
// A per-tick steering force contributor evaluated by SteerArbitrator.
// Return null from calculate() if the rule has nothing to say this tick.
interface SteerRule {
val entity: PokemonEntity
// Higher = evaluated first, consumes force budget before lower priority rules.
// 90-100: obstacle avoidance
// 60-89: threat / boundary
// 30-59: social (separation, alignment, cohesion)
// 0-29: goal / wander
val priority: Int
// Multiplied against the rule output before budget accounting.
val weight: Float
// RGB 0-1 for the debug line drawn by SteerArbitrator.
val debugColor: Triple<Float, Float, Float> get() = Triple(1f, 1f, 1f)
fun calculate(): Vec3?
}
@@ -1,76 +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.entity.ai.steering.rules
import com.cobblemon.mod.common.entity.ai.steering.SteerRule
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
import com.cobblemon.mod.common.entity.pokemon.extensions.steerToTarget
import net.minecraft.world.phys.Vec3
import kotlin.math.max
import kotlin.math.sin
import kotlin.math.sqrt
import kotlin.math.cos
// Forward AABB projection obstacle avoidance. Stateful — one instance per entity.
class ObstacleAvoidRule(
override val entity: PokemonEntity,
override val priority: Int = 100,
override val weight: Float = 1.0f,
override val debugColor: Triple<Float, Float, Float> = Triple(1f, 0f, 0f),
val maxForce: Double = 0.02,
val lookAheadTicks: Int = 10,
val smoothingAlpha: Double = 0.25
) : SteerRule {
private var prevForce: Vec3 = Vec3.ZERO
override fun calculate(): Vec3? {
val topSpeed = (entity.moveControl as? PokemonMoveControl)?.steerSpeed ?: 0.1
val forwardVec = if (entity.deltaMovement.horizontalDistanceSqr() < 0.001) {
val yaw = Math.toRadians(entity.yRot.toDouble())
Vec3(-sin(yaw), 0.0, cos(yaw))
} else {
Vec3(entity.deltaMovement.x, 0.0, entity.deltaMovement.z).normalize()
}
val lookAheadDist = max(entity.deltaMovement.length() * lookAheadTicks, entity.bbWidth / 2.0)
val collBox = entity.boundingBox.move(forwardVec.scale(lookAheadDist))
val shapes = entity.level().getBlockCollisions(entity, collBox)
val nearestShape = shapes.minByOrNull { shape ->
shape.bounds().center.distanceToSqr(entity.position())
}
if (nearestShape == null) {
prevForce = prevForce.lerp(Vec3.ZERO, smoothingAlpha)
return if (prevForce.lengthSqr() < 1e-6) null else prevForce
}
val obsCenter = nearestShape.bounds().center
val toObs = obsCenter.subtract(entity.position())
val projVec = forwardVec.scale(toObs.dot(forwardVec))
val lateralComponent = toObs.subtract(projVec)
val avoidForce = if (lateralComponent.lengthSqr() < 0.001) {
// Dead ahead — turn right
val rightVec = forwardVec.cross(Vec3(0.0, 1.0, 0.0))
entity.steerToTarget(entity.position().add(rightVec), topSpeed, maxForce, horzOnly = true)
} else {
var avoidanceVec = Vec3(lateralComponent.x * -1.0, 0.0, lateralComponent.z * -1.0)
val avoidStrength = sqrt(1.0 - (avoidanceVec.length() / (entity.bbWidth / 2.0 + 0.5)).coerceIn(0.0, 0.7))
val avoidancePoint = entity.position().add(avoidanceVec)
entity.steerToTarget(avoidancePoint, topSpeed, maxForce * avoidStrength, horzOnly = true)
}
prevForce = prevForce.lerp(avoidForce, smoothingAlpha)
return prevForce
}
}
@@ -1,35 +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.entity.ai.steering.rules
import com.cobblemon.mod.common.entity.ai.steering.SteerRule
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
import com.cobblemon.mod.common.entity.pokemon.extensions.steerToTarget
import net.minecraft.world.phys.Vec3
// Steers toward a target position. Reads speed from PokemonMoveControl.steerSpeed.
// Return null from targetProvider to deactivate for a tick.
class SeekRule(
override val entity: PokemonEntity,
override val priority: Int = 10,
override val weight: Float = 1.0f,
override val debugColor: Triple<Float, Float, Float> = Triple(0f, 1f, 1f),
val maxForce: Double,
val horzOnly: Boolean = false,
val arrivalRange: Double? = null,
val targetProvider: (PokemonEntity) -> Vec3?
) : SteerRule {
override fun calculate(): Vec3? {
val target = targetProvider(entity) ?: return null
val speed = (entity.moveControl as? PokemonMoveControl)?.steerSpeed ?: 0.1
return entity.steerToTarget(target, speed, maxForce, arrivalRange, horzOnly)
}
}
@@ -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.entity.ai.steering.rules
import com.cobblemon.mod.common.entity.ai.steering.SteerRule
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
import com.cobblemon.mod.common.entity.pokemon.extensions.steerToTarget
import net.minecraft.world.phys.Vec3
import kotlin.math.sin
// Steers toward a point directly ahead of the entity's current velocity/yaw.
// Useful as a baseline test rule.
class WalkForwardRule(
override val entity: PokemonEntity,
override val priority: Int = 10,
override val weight: Float = 1.0f,
override val debugColor: Triple<Float, Float, Float> = Triple(0f, 1f, 0f),
val maxForce: Double = 0.02
) : SteerRule {
override fun calculate(): Vec3? {
val speed = (entity.moveControl as? PokemonMoveControl)?.steerSpeed ?: 0.1
val forwardVec = if (entity.deltaMovement.horizontalDistanceSqr() < 0.001) {
val yaw = Math.toRadians(entity.yRot.toDouble())
Vec3(-sin(yaw), 0.0, cos(yaw))
} else {
Vec3(entity.deltaMovement.x, 0.0, entity.deltaMovement.z).normalize()
}
val pointAhead = entity.position().add(forwardVec)
return entity.steerToTarget(pointAhead, speed, maxForce, horzOnly = true)
}
}
private fun cos(d: Double) = kotlin.math.cos(d)
private fun sin(d: Double) = kotlin.math.sin(d)
@@ -1,71 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.entity.ai.steering.rules
import com.cobblemon.mod.common.entity.ai.steering.SteerRule
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
import com.cobblemon.mod.common.entity.pokemon.extensions.steerToTarget
import net.minecraft.util.Mth
import net.minecraft.world.phys.Vec3
import kotlin.math.abs
import kotlin.math.sin
import kotlin.random.Random
// Reynolds wander — projects a sphere ahead and offsets a point on it each tick.
// Stateful: holds current wander angles, one instance per entity.
// https://slsdo.github.io/steering-behaviors/
class WanderRule(
override val entity: PokemonEntity,
override val priority: Int = 10,
override val weight: Float = 1.0f,
override val debugColor: Triple<Float, Float, Float> = Triple(1f, 0.5f, 0f),
val maxForce: Double = 0.02,
val wanderDisp: Double = 15.0,
val centerDistance: Double = 4.0,
val wanderRadius: Double = 4.0,
val horzOnly: Boolean = false //TODO: all of these should be checks if flying or walking
) : SteerRule {
var currHorzWander = 0.0
var currVertWander = 0.0
override fun calculate(): Vec3? {
val speed = (entity.moveControl as? PokemonMoveControl)?.steerSpeed ?: 0.1
val normVec = if (entity.deltaMovement.lengthSqr() > 0.0001) {
entity.lookAngle.normalize()
} else {
Vec3(
Random.nextDouble(-1.0, 1.0),
Random.nextDouble(-1.0, 1.0),
Random.nextDouble(-1.0, 1.0)
).normalize()
}
var wanderOff = normVec
// Clamp vertical wander when getting too steep
val currPitchS = sin(Mth.atan2(wanderOff.y, wanderOff.horizontalDistance()))
if (currPitchS >= 0.5f || currPitchS <= -0.5f) currVertWander = 0.0
wanderOff = wanderOff.xRot(Math.toRadians(currVertWander).toFloat())
wanderOff = wanderOff.yRot(Math.toRadians(currHorzWander).toFloat())
val wanderCenter = entity.position().add(normVec.scale(centerDistance))
val wanderPoint = wanderCenter.add(wanderOff.scale(wanderRadius))
// Advance wander angles
currVertWander = Mth.wrapDegrees(currVertWander + Random.nextDouble(-wanderDisp, wanderDisp))
currHorzWander = Mth.wrapDegrees(currHorzWander + Random.nextDouble(-wanderDisp, wanderDisp))
val force = entity.steerToTarget(wanderPoint, speed, maxForce)
return if (horzOnly) Vec3(force.x, 0.0, force.z) else force
}
}
@@ -27,7 +27,6 @@ import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluenc
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.position.FishingSpawnablePosition
import com.cobblemon.mod.common.api.spawning.spawner.FishingSpawnerFactory
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.client.sound.EntitySoundTracker
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
@@ -763,6 +762,7 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
lureLevel: Int
) {
val spawner = BestSpawner.fishingSpawner
val bucketInfluence = BucketNormalizingInfluence(tier = lureLevel + luckOfTheSeaLevel)
val spawnCause = FishingSpawnCause(
spawner = spawner,
@@ -771,21 +771,14 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
lureLevel = lureLevel,
)
val ctx = FishingSpawnerFactory.Context(
player = player,
rodStack = rodItemStack,
lureLevel = lureLevel,
luckOfTheSeaLevel = luckOfTheSeaLevel,
world = level() as ServerLevel,
pos = position().toBlockPos(),
spawner = spawner
)
val spawnablePosition = FishingSpawnablePosition(
cause = spawnCause,
world = ctx.world,
pos = ctx.pos,
influences = FishingSpawnerFactory.buildPositionInfluences(ctx)
world = level() as ServerLevel,
pos = position().toBlockPos(),
influences = mutableListOf(
PlayerLevelRangeInfluence(player, TYPICAL_VARIATION),
bucketInfluence
)
)
val result = spawner.calculateSpawnActionForPosition(
@@ -164,7 +164,6 @@ import net.minecraft.world.item.ItemUtils
import net.minecraft.world.item.Items
import net.minecraft.world.level.Level
import net.minecraft.world.level.LightLayer
import net.minecraft.world.level.block.HorizontalDirectionalBlock
import net.minecraft.world.level.block.SuspiciousEffectHolder
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.gameevent.GameEvent
@@ -175,7 +174,10 @@ import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.util.*
import java.util.concurrent.CompletableFuture
import kotlin.math.*
import kotlin.math.PI
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
@Suppress("unused")
open class PokemonEntity(
@@ -211,7 +213,6 @@ open class PokemonEntity(
@JvmStatic var RIDE_BOOSTS = SynchedEntityData.defineId(PokemonEntity::class.java, RideBoostsDataSerializer)
@JvmStatic var RIDE_STAMINA = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.FLOAT)
@JvmStatic var SCALE_MODIFIER = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.FLOAT)
@JvmStatic val IS_SPRINTING = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.BOOLEAN)
const val BATTLE_LOCK = "battle"
const val EVOLUTION_LOCK = "evolving"
@@ -291,9 +292,6 @@ open class PokemonEntity(
var shownItem: ItemStack
get() = entityData.get(SHOWN_HELD_ITEM)
set(value) = entityData.set(SHOWN_HELD_ITEM, value)
var isPokemonSprinting: Boolean
get() = entityData.get(IS_SPRINTING)
set(value) { entityData.set(IS_SPRINTING, value) }
var lastLightningBoltUUID: UUID? = null
@@ -462,7 +460,6 @@ open class PokemonEntity(
builder.define(RIDE_BOOSTS, emptyMap())
builder.define(RIDE_STAMINA, 1F)
builder.define(SCALE_MODIFIER, 1F)
builder.define(IS_SPRINTING, false)
}
override fun onSyncedDataUpdated(data: EntityDataAccessor<*>) {
@@ -625,12 +622,8 @@ open class PokemonEntity(
isPokemonFlying = flyDist - flyDistO > 0.005F
isPokemonWalking = walkDist - walkDistO > 0.005F
// TODO: Figure out a better way to allow for this. Or maybe just always do the animations data accumulation its really not that bad
if (this.pokemon.species.name.lowercase() == "charizard" || (passengers.isNotEmpty() && level().isClientSide)) {
// This is so ugly why am I doing it like this... even if its for a test this is low
if (passengers.isNotEmpty() && level().isClientSide) {
rideSoundManager.tick()
}
if (passengers.isNotEmpty() && level().isClientSide) {
rideSoundManager.tick()
ridingAnimationData.update()
} else if (!passengers.isNotEmpty() && level().isClientSide) {
rideSoundManager.stop()
@@ -684,9 +677,12 @@ open class PokemonEntity(
yBodyRot = (spawnDirection * 1000F).toInt() / 1000F
}
jumping = false
if (this.tethering != null && !this.tethering!!.box.contains(this.x, this.y, this.z)) {
this.tethering = null
this.pokemon.recall()
}
checkPastureTether()
jumping = false
//This is so that pokemon in the pasture block are ALWAYS in sync with the pokemon box
//Before, pokemon entities in pastures would hold an old ref to a pokemon obj and changes to that would not appear to the underlying file
@@ -709,40 +705,6 @@ open class PokemonEntity(
schedulingTracker.update(1 / 20F)
}
// Check to see if the entity needs recalled or repositioned if pastured.
fun checkPastureTether() {
// Teleport a pastured mon back to the pasture block if they are out of range
if (this.tethering != null && !this.tethering!!.box.contains(this.x, this.y, this.z)) {
// Gather the ideal position (behind the pastureBlock)
val pastureBlockPos = this.tethering!!.pasturePos
val state = this.level().getBlockState(pastureBlockPos)
// Check to ensure we are working with a pastureblock here and it hasn't been broken
if (state.block == CobblemonBlocks.PASTURE) {
val direction = state.getValue(HorizontalDirectionalBlock.FACING)
val width = this.boundingBox.xsize
val tpPos = pastureBlockPos.offset(direction.normal.multiply(ceil(width).toInt() + 1)).center
val heightAllowance = 4.0 // Allow spawning up to x blocks above the pastureBlock y level
// Attempt tp and recall if it fails
if (!this.randomTeleport(tpPos.x, tpPos.y + heightAllowance, tpPos.z, false)) {
// If the teleport was not successful then recall the mon
this.tethering = null
this.pokemon.recall()
} else {
// Stop any now invalid navigation post teleport
this.navigation.stop()
}
} else {
// If the block is destroyed or something else went wrong.
this.tethering = null
this.pokemon.recall()
}
}
}
override fun customServerAiStep() {
this.getBrain().tick(level() as ServerLevel, this)
// PokemonBrain.updateActivities(this)
@@ -2157,9 +2119,7 @@ open class PokemonEntity(
override fun stopSeenByPlayer(player: ServerPlayer) {
if (this.ownerUUID == player.uuid && tethering == null) {
// queuedToDespawn = true
if (this.removalReason != RemovalReason.DISCARDED) {
this.remove(RemovalReason.DISCARDED)
}
this.remove(RemovalReason.DISCARDED)
return
}
}
@@ -1,547 +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.entity.pokemon.ai
import com.cobblemon.mod.common.CobblemonActivities
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToTrackingPlayers
import com.cobblemon.mod.common.client.render.debug.EntityDebugLine
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.extensions.*
import com.cobblemon.mod.common.net.messages.client.debug.ClientboundUpdateObsAvoidPacket
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.resolveDouble
import net.minecraft.util.Mth
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.control.MoveControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.level.ClipContext
import net.minecraft.world.phys.HitResult
import net.minecraft.world.phys.Vec3
import kotlin.math.*
import kotlin.random.Random
class BoidsMoveControl(val pokemonEntity: PokemonEntity, val target: LivingEntity) : MoveControl(pokemonEntity) {
companion object {
const val VERY_CLOSE = 2.500000277905201E-3
const val MAX_SPEED = 0.3 / 2
const val MAX_FORCE = 0.02
const val PREDATOR_MAX_SPEED = 0.6
// const val MAX_SPEED = 0.2
// const val MAX_FORCE = 0.013
}
// TODO: might need to hold its own velocity so minecraft doesn't do its nonsense to it?
// Can handle collisions ourselves as well
var speed: Double? = null
var drawLines: MutableList<EntityDebugLine> = mutableListOf()
// wander vars
var currHorzWander = 0.0
var currVertWander = 0.0
val wanderDisp = 15.0 // The degrees of change from tick to tick in wander angle
override fun tick() {
// Clear since the info is sent and is now stale
drawLines.clear()
// Steering constants
val orbitRadius = 16.0
val targetPos = target.position().add(0.0, 4.0, 0.0)
val arrivalRange = 2.0 // in blocks
val species = pokemonEntity.pokemon.species.name
// Set this to ensure the flying pose is active
// ignore all the friction stuff from outside
speed?.let { pokemonEntity.setDeltaMovement(pokemonEntity.deltaMovement.normalize().scale(it)) }
// Constrain to rectangular boundary
val cubeWidth = 16.0
val cubeHeight = 16.0
val cubeCenter = target.position().add(0.0, cubeHeight / 2.0, 0.0)
//forceRectBoundary(cubeCenter, cubeWidth, cubeHeight)
// Apply boid forces
// Obstacle Avoidance
val whiskerRange = 1.0
val avoidanceAngle = 20.0 // x degrees to the left, right, up, and down
//val obsAvoidForce = whisObsAvoid(whiskerRange, avoidanceAngle)
// if (obsAvoidForce != null) {
// pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(obsAvoidForce.scale(0.5))
// }
// TODO: obviously don't hardcode each pokemon. Remove this after testing is finished.
if (pokemonEntity.pokemon.species.name.lowercase() == "charizard") {
pokemonEntity.setFlying(true)
pokemonEntity.resetFallDistance()
seekPrey(pokemonEntity)
} else if (pokemonEntity.pokemon.species.name.lowercase() == "garchomp") {
pokemonEntity.setFlying(false)
val walkSpeed = pokemonEntity.runtime.resolveDouble(pokemonEntity.behaviour.moving.walk.walkSpeed) * 1.5
val steerForce = pokemonEntity.steerToTarget(target.position(), walkSpeed, walkSpeed / 12)
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(steerForce.x, 0.0, steerForce.z)
// speed?.let { this.mob.setZza(speed!!.toFloat()) }
} else if (pokemonEntity.pokemon.species.name.lowercase() == "skiddo") {
pokemonEntity.setFlying(false)
//wander(pokemonEntity,1.0)
// val steerForce = pokemonEntity.steerToTargetForce(target.position(), MAX_SPEED, MAX_FORCE)
// pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(steerForce.x, 0.0, steerForce.z)
aviodPredators(pokemonEntity, includePlayer = true)
boid(isFlyingOrSwimming = false)
} else {
pokemonEntity.setFlying(true)
pokemonEntity.resetFallDistance()
wander(pokemonEntity,0.8)
boid()
aviodPredators(pokemonEntity, includePlayer = true)
// Force towards ground
forceRectBoundary(pokemonEntity, cubeCenter, cubeWidth, cubeHeight)
}
// val avoidForce = avoidTarget(target.position(), MAX_SPEED, MAX_FORCE, 10.0)
// pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(avoidForce.scale(1.0))
// Apply steering force to current movement
// val dm = pokemonEntity.deltaMovement
// val w_pos = pokemonEntity.position().add(Vec3(dm.x, 0.0, dm.z))
// val steerForce = steerToTargetForce(w_pos, MAX_SPEED, MAX_FORCE)
// pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(steerForce)
// Take note of speed again to avoid minecraft's friction logic
speed = pokemonEntity.deltaMovement.length() * 0.98
// Test out what this setting of speed does.
//speed?.let { this.mob.speed = speed!!.toFloat() }
// Limit upwards speed to be half of max speed. The boids kept bumping into the top of the box more so than birds
// would. Honestly birds probably mostly want to move in the x,z plane anyhow
// pokemonEntity.deltaMovement = Vec3(
// pokemonEntity.deltaMovement.x,
// min(pokemonEntity.deltaMovement.y, MAX_SPEED * 0.5),
// pokemonEntity.deltaMovement.y
// ).normalize().scale(speed!!)
pokemonEntity.orientEntityToTravel(0.4f)
if (false && drawLines.isNotEmpty()) { //TODO: Re-enable
sendPacketToTrackingPlayers(pokemonEntity, ClientboundUpdateObsAvoidPacket(pokemonEntity.id, drawLines))
}
}
private fun aviodPredators(entity: PokemonEntity, includePlayer: Boolean = false) {
val fearRadius = 5.0
val brain = entity.brain
val predators = brain.getMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES).map { nearbyEntities ->
nearbyEntities.filterIsInstance<PokemonEntity>().filter { pokemon ->
pokemon.brain.activeNonCoreActivity.orElse(null) == CobblemonActivities.POKEMON_BOIDS &&
pokemon.pokemon.species.name.lowercase() == "charizard" &&
entity.position().subtract(pokemon.position()).length() <= fearRadius
}
}.orElse(emptyList())
var totalEvasionVec = Vec3.ZERO
var predatorCount = predators.size
// If the player should be included in avoidance then add the player as a predator.
if (includePlayer) {
totalEvasionVec = totalEvasionVec.add(entity.avoidTarget(target.position(), MAX_SPEED * 1.2, MAX_FORCE * 2, fearRadius))
predatorCount += 1
}
// Average evasion forces for all predators in the area and apply it to the prey entity
if (predatorCount > 0) {
for (predator in predators) {
totalEvasionVec = totalEvasionVec.add(entity.avoidTarget(predator.position(), MAX_SPEED * 1.2, MAX_FORCE * 2, fearRadius))
}
totalEvasionVec = totalEvasionVec.scale(1.0 / predatorCount)
if (entity.isFlying() || entity.isSwimming) {
entity.deltaMovement = entity.deltaMovement.add(totalEvasionVec)
} else {
entity.deltaMovement = entity.deltaMovement.add(Vec3(totalEvasionVec.x, 0.0, totalEvasionVec.z))
}
}
}
/*************************************************************************************************************
Seek the closest prey and pursue
*************************************************************************************************************/
private fun seekPrey(predator: PokemonEntity) {
val SeekRadius = 20.0
val brain = predator.brain
// Do calcs for head height as it looks better this way than a charizard flying crotch first at a group of pidgeys
val kindaHeadHeight = predator.position()
val prey = brain.getMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES).map { nearbyEntities ->
nearbyEntities.filterIsInstance<PokemonEntity>().filter { pokemon ->
pokemon.brain.activeNonCoreActivity.orElse(null) == CobblemonActivities.POKEMON_BOIDS &&
(pokemon.pokemon.species.name.lowercase() == "pidgey" || pokemon.pokemon.species.name.lowercase() == "skiddo") &&
kindaHeadHeight.subtract(pokemon.position()).length() <= SeekRadius
}
}.orElse(emptyList())
// Find the closest prey and seek towards it
val nearestPrey = prey.minByOrNull { pokePrey ->
kindaHeadHeight.subtract(pokePrey.position()).length()
}
nearestPrey?.let { prey ->
// Do the actual attack
// TODO: make this not dumb
if(kindaHeadHeight.subtract(nearestPrey.position()).length() < 0.5 + predator.bbWidth + nearestPrey.bbWidth) {
//predator.doHurtTarget(nearestPrey)
}
// Steer towards the target
val steerForce = predator.steerToTarget(prey.position(), PREDATOR_MAX_SPEED, MAX_FORCE)
predator.deltaMovement = predator.deltaMovement.add(steerForce)
}
}
/*************************************************************************************************************
Whisker Obstacle Avoidance
This function ray casts in a cone in front of the entity
*************************************************************************************************************/
private fun whisObsAvoid(range: Double, lookWidth: Double): Vec3? {
// --- 1. Build the Orientation Matrix ---
val forward = pokemonEntity.lookAngle.scale(range)
// val tempUp = if (abs(forward.y) > 0.999) Vec3(0.0, 0.0, 1.0) else Vec3(0.0, 1.0, 0.0)
// val right = forward.cross(tempUp).normalize()
// val up = right.cross(forward).normalize()
//
// val orientation = Matrix3f()
// .setColumn(0, Vector3f(right.x.toFloat(), right.y.toFloat(), right.z.toFloat()))
// .setColumn(1, Vector3f(up.x.toFloat(), up.y.toFloat(), up.z.toFloat()))
// .setColumn(2, Vector3f(forward.x.toFloat(), forward.y.toFloat(), forward.z.toFloat()))
// --- 2. Define Whiskers in Simple, Local Space ---
val radLookWidth = lookWidth.toRadians().toFloat()
// val localWhiskers: List<Vector3f> = listOf(
// Vector3f(0f, 0f, 1f), // Forward
//// Vector3f(sin(radLookWidth), 0f, cos(radLookWidth)), // Left
//// Vector3f(-sin(radLookWidth), 0f, cos(radLookWidth)), // Right
//// Vector3f(0f, sin(radLookWidth), cos(radLookWidth)), // Up
//// Vector3f(0f, -sin(radLookWidth), cos(radLookWidth)) // Down
// )
//
// // --- 3. Transform Local Whiskers to World Space using the Matrix ---
// val whiskerOffsets = localWhiskers.map { localVec ->
// orientation.transform(localVec, Vector3f()).toVec3d().scale(range) // Transform and store in a new vector
// }
// Obtain all points to be raycasted to
val scaledLookVec = pokemonEntity.deltaMovement.normalize().scale(range)
val lookPoints: List<Vec3> = listOf(
forward,
// forward.yRot(radLookWidth),
// forward.yRot(-radLookWidth),
// forward.xRot(90.toRadians()),
// forward.xRot((-90).toRadians()),
)
// iterate through each point and raycast to it starting from the entities pos (may need to be from somewhere else)
// If a position is hit then add its avoidance force to the totalAvoidance forces.
var totalAvoidance: Vec3? = null
val level = pokemonEntity.level()
val startPos = pokemonEntity.position()
for (point in lookPoints) {
val endPos = startPos.add(point)
val hit = level.clip(
ClipContext(
startPos,
endPos,
ClipContext.Block.OUTLINE, // If this is being weird then go back to COLLIDER
ClipContext.Fluid.ANY, // Birds should probably avoid fluid
pokemonEntity
)
)
// Add the whisker to the debug lines to be drawn
drawLines.add(EntityDebugLine(endPos, 1.0f, 0.0f, 0.0f))
//visualizeRay(level, startPos, endPos, hit.type != HitResult.Type.MISS)
if (hit.type != HitResult.Type.MISS) {
// Get the aviodance vector as the vector from the block detection point
// to the pokemon.
// Also inversely scale the size of the vector based on the distance the pokemon
// is to the object. This means close obstacles are avoided more strongly
val hitDist = hit.location.distanceTo(pokemonEntity.eyePosition)
val avoidVec = startPos.subtract(endPos).normalize() //.scale(1.0 - (hitDist / range))
// Add avoid vec to total
totalAvoidance = totalAvoidance?.add(avoidVec) ?: avoidVec
}
}
// // Scale all forces down to the max foce
// if (totalAvoidance != null) {
// // Cap the max total avoidance desire
// if (totalAvoidance.length() > MAX_SPEED) totalAvoidance = totalAvoidance.normalize().scale(MAX_SPEED)
// // Convert to Reynolds steering force
// totalAvoidance = totalAvoidance.subtract(pokemonEntity.deltaMovement)
// // Cap the max total avoidance force
// if (totalAvoidance.length() > MAX_FORCE) totalAvoidance = totalAvoidance.normalize().scale(MAX_FORCE)
// } // Is this next one even cleaner?
return totalAvoidance?.let { desiredVelocity ->
// Cap the desired velocity (using lengthSqr is more efficient than length)
val cappedVelocity = if (desiredVelocity.lengthSqr() > MAX_SPEED * MAX_SPEED) {
desiredVelocity.normalize().scale(MAX_SPEED)
} else {
desiredVelocity
}
// Convert to Reynolds steering force
val steeringForce = cappedVelocity.subtract(pokemonEntity.deltaMovement)
// Cap the final steering force
if (steeringForce.lengthSqr() > MAX_FORCE * MAX_FORCE) {
steeringForce.normalize().scale(MAX_FORCE)
} else {
steeringForce
}
}
}
private fun wander(entity: PokemonEntity, forceScale: Double = 1.0) {
// Wander behaviour
/*************************************************************************************************************
* The wander behaviour is based of Reynolds wander behaviour which can be seen in the below link under wander
* This version however is adapted to 3dimensions.
* https://slsdo.github.io/steering-behaviors/
*************************************************************************************************************/
// Get curr steering positions in left/right and up/down offsets
val normVec = if(entity.deltaMovement.lengthSqr() > 0.0001) {
entity.lookAngle.normalize()
} else {
Vec3(
Random.nextDouble(-1.0, 1.0),
Random.nextDouble(-1.0, 1.0),
Random.nextDouble(-1.0, 1.0)
).normalize()
}
var wanderOff = normVec
val currPitchS = sin(Mth.atan2(wanderOff.y, wanderOff.horizontalDistance()))
if (currPitchS >= 0.5f || currPitchS <= -0.5f) { //TODO: make this y limit class wide
this.currVertWander = 0.0
}
wanderOff = wanderOff.xRot(this.currVertWander.toRadians())
wanderOff = wanderOff.yRot(this.currHorzWander.toRadians())
// Base the center off the current direction of travel
val centerDistance = 4.0 // How many blocks the wander 'sphere' is in front of the entity
val wanderCenter = entity.position().add(normVec.scale(centerDistance))
// Get the wander circle's radius
val wanderRadius = 4.0
val wanderPoint = wanderCenter.add(wanderOff.scale(wanderRadius))
// change wander points
val randVert = Random.nextDouble(-wanderDisp, wanderDisp)
val randHorz = Random.nextDouble(-wanderDisp, wanderDisp)
currVertWander = Mth.wrapDegrees(randVert + currVertWander)
currHorzWander = Mth.wrapDegrees(randHorz + currHorzWander)
drawLines.add(EntityDebugLine(wanderPoint.subtract(pokemonEntity.position()), 1.0f, 0.0f, 0.0f, 1.0f)) // Add WanderPoint
drawLines.add(EntityDebugLine(wanderCenter.subtract(pokemonEntity.position()), 0.0f, 1.0f, 0.0f, 1.0f)) // Add wander center
val wanderForce = entity.steerToTarget(wanderPoint, MAX_SPEED, MAX_FORCE)
if(pokemonEntity.isFlying() || pokemonEntity.isSwimming) {
entity.deltaMovement = pokemonEntity.deltaMovement.add(wanderForce.scale(forceScale))
} else {
entity.deltaMovement = pokemonEntity.deltaMovement.add(Vec3(wanderForce.x, 0.0, wanderForce.z).scale(forceScale))
}
}
private fun boid(isFlyingOrSwimming: Boolean = true) {
// TODO: maybe move this to a sensor that lives spins up on the boid activity creation
// Get a list of other boid entities in this entity's vicinity
val brain = pokemonEntity.brain
val boids = brain.getMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES).map { nearbyEntities ->
nearbyEntities.filterIsInstance<PokemonEntity>().filter { pokemon ->
pokemon.brain.activeNonCoreActivity.orElse(null) == CobblemonActivities.POKEMON_BOIDS
}
}.orElse(emptyList())
// separation
val separationForce = separation(boids)?.scale(0.8)
separationForce?.let { force ->
if( isFlyingOrSwimming) {
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(force)
} else {
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(Vec3(force.x, 0.0, force.z))
}
}
// alignment
val alignmentForce = alignment(boids)?.scale(0.0)
alignmentForce?.let { force ->
if( isFlyingOrSwimming) {
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(force)
} else {
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(Vec3(force.x, 0.0, force.z))
}
}
// cohesion
val cohesionForce = cohesion(boids)?.scale(0.6)
cohesionForce?.let { force ->
if( isFlyingOrSwimming) {
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(force)
} else {
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(Vec3(force.x, 0.0, force.z))
}
}
}
private fun separation(boids: List<PokemonEntity>): Vec3? {
var seperationVec: Vec3? = null
// Gather the total separation vec of all close entities
boids.forEach { boid ->
val toTargetVec = pokemonEntity.position().subtract(boid.position())
val desiredSeperation = boid.bbWidth * 2.0 // Base the seperation distance on the model width
val currDist = toTargetVec.length()
if (currDist < desiredSeperation) {
if (seperationVec == null) seperationVec = Vec3.ZERO
// Make the seperation force inversely proprotional to the serperation distance
// Also, scale the force by the bbwidth of the model so
seperationVec = seperationVec.add(toTargetVec.normalize().scale((1.0 - (currDist / desiredSeperation)) ))
}
}
if (seperationVec != null) {
//if (seperationVec.length() > MAX_SPEED) seperationVec = seperationVec.normalize().scale(MAX_SPEED)
seperationVec = seperationVec.normalize().scale(MAX_SPEED)
seperationVec = seperationVec.subtract(pokemonEntity.deltaMovement)
if (seperationVec.length() > MAX_FORCE) {
seperationVec = seperationVec.normalize().scale(MAX_FORCE)
}
}
return seperationVec
}
private fun alignment(boids: List<PokemonEntity>): Vec3? {
val neighborDist = 4.0
var summedVel: Vec3? = null
var alignmentVec: Vec3? = null
var boidCount = 0
// Gather the average position of the boid
boids.forEach { boid ->
val vecToOther = boid.position().subtract(this.pokemonEntity.position())
val distToOther = vecToOther.length()
val widthOfViewInDeg = 180
val isInSightLine = pokemonEntity.deltaMovement.normalize().dot(vecToOther) > cos((widthOfViewInDeg / 2.0).toRadians())
if (isInSightLine && distToOther < neighborDist) {
if (summedVel == null) summedVel = Vec3.ZERO
summedVel = summedVel.add(boid.deltaMovement.normalize())
boidCount++
}
}
if (summedVel != null) {
// Get the average vel/alignment by dividing by the number of boids sampled
val averageVel = summedVel.scale(1.0 / boidCount)
//alignmentVec = if (averageVel.length() > MAX_SPEED) averageVel.normalize().scale(MAX_SPEED) else averageVel
alignmentVec = averageVel.normalize().scale(MAX_SPEED)
alignmentVec = alignmentVec.subtract(pokemonEntity.deltaMovement)
if (alignmentVec.length() > MAX_FORCE) {
alignmentVec = alignmentVec.normalize().scale(MAX_FORCE)
}
}
return alignmentVec
}
private fun cohesion(boids: List<PokemonEntity>): Vec3? {
//val neighborDist = 5.0
var summedPos: Vec3? = null
var cohesionVec: Vec3? = null
var boidCount = 0
val cohesionRadius = 8.0
// Gather the average position of the boid
boids.forEach { boid ->
val vecToOther = boid.position().subtract(this.pokemonEntity.position())
val distToOther = vecToOther.length()
val widthOfViewInDeg = 360
val isInSightLine = pokemonEntity.deltaMovement.normalize().dot(vecToOther) > cos((widthOfViewInDeg / 2.0).toRadians())
if (isInSightLine && distToOther < cohesionRadius) { // Only use members that are within a certain radius and eyeline
if (summedPos == null) summedPos = Vec3.ZERO
summedPos = summedPos.add(boid.position())
boidCount++
}
}
if (summedPos != null) {
// Get the average position by dividing by the number of boids sampled
val averagePos = summedPos.scale(1.0 / boidCount)
// Get the vector towards that average position and scale
cohesionVec = averagePos.subtract(pokemonEntity.position())
//if (cohesionVec.length() > MAX_SPEED) cohesionVec = cohesionVec.normalize().scale(MAX_SPEED)
cohesionVec = cohesionVec.normalize().scale(MAX_SPEED)
cohesionVec = cohesionVec.subtract(pokemonEntity.deltaMovement)
if (cohesionVec.length() > MAX_FORCE) {
cohesionVec = cohesionVec.normalize().scale(MAX_FORCE)
}
}
return cohesionVec
}
private fun forceRectBoundary(entity: PokemonEntity, basePos: Vec3, rectWidth: Double, rectHeight: Double) {
val maxBoundaryForce = MAX_FORCE //* 2.0
val correctiveForce = getRectCorrectiveForce(basePos, rectWidth, rectHeight)
if (correctiveForce != null) {
//val correctiveForce = steerToTargetForce(correctivePos, speedLimit, maxForce)
var steer = correctiveForce.subtract(entity.deltaMovement)
if (steer.length() > maxBoundaryForce) {
steer = steer.normalize().scale(maxBoundaryForce)
}
entity.setDeltaMovement(entity.deltaMovement.add(steer))
}
}
// Returns the desired force to correct the entity back into the rectangle area
private fun getRectCorrectiveForce( basePos: Vec3, rectWidth: Double, rectHeight: Double): Vec3? {
val entityPos = pokemonEntity.position()
val posFromBase = entityPos.subtract(basePos)
val cubeHalfWidth = rectWidth / 2.0 // Useful as the basePoint is in the middle of the cube
val cubeHalfHeight = rectHeight / 2.0
// Check the three possible faces for exceeding the boundary (x, y, and z faces of cube)
val xExceed = max(0.0, abs(posFromBase.x) - cubeHalfWidth)
val yExceed = max(0.0, abs(posFromBase.y) - cubeHalfHeight)
val zExceed = max(0.0, abs(posFromBase.z) - cubeHalfWidth)
return if ( xExceed == 0.0 && yExceed == 0.0 && zExceed == 0.0) {
null
} else {
var desiredPos = pokemonEntity.position().add(pokemonEntity.deltaMovement) // Add delta movement so we aren't slowing this guy down
if (xExceed != 0.0) desiredPos = Vec3( basePos.x, desiredPos.y, desiredPos.z)
if (yExceed != 0.0) desiredPos = Vec3( desiredPos.x, basePos.y, desiredPos.z)
if (zExceed != 0.0) desiredPos = Vec3( desiredPos.x, desiredPos.y, basePos.z)
return desiredPos.subtract(pokemonEntity.position()).normalize().scale(MAX_SPEED)
}
}
}
//val desiredScale = if (distToTarget > slowDownRadius) speedLimit else (distToTarget/slowDownRadius).pow(2) * speedLimit
//desiredVec = desiredVec.normalize().scale(desiredScale)
@@ -9,47 +9,30 @@
package com.cobblemon.mod.common.entity.pokemon.ai
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToTrackingPlayers
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.client.render.debug.EntityDebugLine
import com.cobblemon.mod.common.client.render.debug.EntityDebugLine.Companion.invoke
import com.cobblemon.mod.common.entity.PlatformType
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.ai.OmniPathNavigation
import com.cobblemon.mod.common.entity.ai.steering.SteerArbitrator
import com.cobblemon.mod.common.entity.ai.steering.rules.ObstacleAvoidRule
import com.cobblemon.mod.common.entity.ai.steering.rules.SeekRule
import com.cobblemon.mod.common.entity.ai.steering.rules.WanderRule
import com.cobblemon.mod.common.entity.ai.steering.rules.WalkForwardRule
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.extensions.*
import com.cobblemon.mod.common.net.messages.client.debug.ClientboundUpdateObsAvoidPacket
import com.cobblemon.mod.common.util.getWaterAndLavaIn
import com.cobblemon.mod.common.util.math.geometry.toDegrees
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.resolveFloat
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.tags.BlockTags
import net.minecraft.tags.FluidTags
import net.minecraft.util.Mth
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.attributes.Attributes
import net.minecraft.world.entity.ai.control.MoveControl
import net.minecraft.world.level.material.FluidState
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.sin
import kotlin.math.sqrt
import kotlin.random.Random
class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemonEntity) {
companion object {
@@ -67,41 +50,6 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
var bankUpwardsBlocksPerTick = 0F
var bankRightDegreesPerTick = 1F
var obsCorrectDir = 0F
var drawLines: MutableList<EntityDebugLine> = mutableListOf()
var prevForce: Vec3? = null
var steerSpeed = this.gatherTopSpeed(pokemonEntity)
private val steerArbitrator by lazy {
val steerArbitrator = SteerArbitrator(
entity = pokemonEntity,
maxForce = 0.02,
rules = mutableListOf(
ObstacleAvoidRule(
entity = pokemonEntity,
debugColor = Triple(1f, 0f, 0f),
),
SeekRule(
entity = pokemonEntity,
priority = 10,
maxForce = 0.02,
debugColor = Triple(0f, 1f, 0f),
horzOnly = true,
targetProvider = { e ->
(e.navigation as? OmniPathNavigation)?.pathFollowTarget //TODO: maybe change this seems silly. Probably want a rule that checks explicitly?
}
),
WanderRule(
entity = pokemonEntity,
debugColor = Triple(0f, 1f, 1f),
horzOnly = true
)
)
)
steerArbitrator
}
fun startBanking(
forwardBlocksPerTick: Float = 0F,
upwardsBlocksPerTick: Float = 0F,
@@ -125,7 +73,6 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
}
override fun tick() {
mob.setDiscardFriction(false) // ignored while trying to move but if stopped or doing something else this needs reenabled
if (banking && operation != Operation.WAIT) {
banking = false
}
@@ -155,7 +102,6 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
val baseSpeed = mob.getAttributeValue(Attributes.MOVEMENT_SPEED).toFloat() * this.speedModifier.toFloat()
val adjustedSpeed = baseSpeed * mediumSpeed
if (banking) {
pokemonEntity.yRot += bankRightDegreesPerTick
pokemonEntity.travel(Vec3(0.0, bankUpwardsBlocksPerTick.toDouble(), bankForwardBlocksPerTick.toDouble()).scale(mediumSpeed.toDouble()))
@@ -164,142 +110,11 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
}
if (bankDurationTicks == 0) {
banking = false
operation = Operation.WAIT
}
}
// Here we call the wander on every pokemon no matter what then they wander then leave
// Just ignore all operatations and do whatever is being tested.
if (true) {
// val horzOnly = true
//
// var topSpeed = gatherTopSpeed(pokemonEntity)
// var maxForce = 0.02 // Arbitrarily chosen as of right now.
// pokemonEntity.isPokemonSprinting = false
//
// // grab forward travel vector direction
// val forwardVec = if (pokemonEntity.deltaMovement.horizontalDistanceSqr() < 0.001) {
// // No meaningful velocity so derive from yaw orientation instead
// val yaw = Math.toRadians(pokemonEntity.yRot.toDouble())
// Vec3(-sin(yaw), 0.0, cos(yaw))
// } else {
// if (horzOnly) Vec3(pokemonEntity.deltaMovement.x, 0.0, pokemonEntity.deltaMovement.z).normalize()
// else pokemonEntity.deltaMovement.normalize()
// }
// val pointAhead = pokemonEntity.position().add(forwardVec)
// val aheadForce = pokemonEntity.steerToTarget(pointAhead, topSpeed, maxForce, horzOnly = horzOnly)
//
//
//// val player = pokemonEntity.level().getNearestPlayer(pokemonEntity, 10.0) ?: return
//// // Flee direction — away from player, flattened to XZ
//// val toPlayerVec = pokemonEntity.position().subtract(player.position())
////
//// if (toPlayerVec.length() < 6.0) {
//// pokemonEntity.isPokemonSprinting = true
////// topSpeed = 0.4 // hardcoded high value
////// maxForce = 0.04
//// topSpeed *= 2.0f
//// maxForce *= 2
//// }
////
//// val fleePoint = pokemonEntity.position().add(toPlayerVec)
//// val aheadForce = pokemonEntity.steerToTarget(fleePoint, topSpeed, maxForce, horzOnly = horzOnly)
//
// // For now just move forward by seeking towards a point ahead
// val lookAheadTicks = 10 // How far in the future of this entities current movement to look ahead for collisions
// val lookAheadDist = max(pokemonEntity.deltaMovement.length() * lookAheadTicks, pokemonEntity.bbWidth / 2.0) // At least always look ahead the width of the mons own hitbox
//
// // Get the collision box
// val inflationAmount = 0.0 //pokemonEntity.bbWidth / 5.0 //TODO: is this needed? it seems to help a bit keeping them off walls but would stop them from entering gaps they truly could
// val collBox = pokemonEntity.boundingBox.move(forwardVec.scale(lookAheadDist)).inflate(inflationAmount, 0.0, inflationAmount) // Inflate a bit
// val shapes = pokemonEntity.level().getBlockCollisions(pokemonEntity, collBox)
//
// // Gather the nearest shape
// val nearestShape = shapes.minByOrNull { shape ->
// shape.bounds().center.distanceToSqr(pokemonEntity.position())
// }
//
// var avoidancForce = Vec3.ZERO
//
// if (nearestShape != null) {
// var hasLeftForce = false
// var hasRightForce = false
// val right = Vec3(-forwardVec.z, 0.0, forwardVec.x) //TODO: expand to 3 dimensions
//
// val obsCenter = nearestShape.bounds().center
// val toObs = obsCenter.subtract(pokemonEntity.position())
//
// // Get the lateral avoidance point to seek to (the avoidance force really)
// // It is the negated vector of toObs - Proj(toObs->forwardVec)
// val projVec = forwardVec.scale(toObs.dot(forwardVec)) // Can do this because forwardVec is normalized
// val lateralComponent = toObs.subtract(projVec) // TODO: moved back so that two opposing forces turn the dude around
//
// avoidancForce = if (lateralComponent.lengthSqr() < 0.001) { // If its dead ahead then just turn right
// val rightVec = forwardVec.cross(Vec3(0.0,1.0,0.0))
// obsCorrectDir = 1F
// pokemonEntity.steerToTarget(pokemonEntity.position().add(rightVec), topSpeed, maxForce, horzOnly = horzOnly)
// } else {
// // Scale the strength of the avoidance vec based off how close to being dead center it is
//
// var avoidanceVec = lateralComponent.scale(-1.0)
// if (horzOnly) avoidanceVec = Vec3(avoidanceVec.x, 0.0, avoidanceVec.z)
// //var avoidStrength = (abs(toObs.dot(avoidanceVec)) / (pokemonEntity.bbWidth / 2.0) ).coerceIn(0.0, 1.0)
//
// // 0.5 to add half the block width allowance since if it catches the corner of a block it still gets the center
// var avoidStrength = sqrt(1 - (avoidanceVec.length() / (pokemonEntity.bbWidth / 2.0 + 0.5) ).coerceIn(0.0, 0.7))
// // Track which side this force is pushing toward
// //val newObsCorrectDir = if (avoidanceVec.normalize().dot(right) > 0) 1F else -1f
//
// // If the new direction is opposite the last direction then invert it
//// if (obsCorrectDir == 0F) {
//// obsCorrectDir = newObsCorrectDir
//// } else if (newObsCorrectDir != obsCorrectDir) {
//// avoidanceVec = avoidanceVec.scale(-1.0)
//// //avoidStrength = 1.0
//// }
//
// val avoidancePoint = pokemonEntity.position().add(avoidanceVec)
// pokemonEntity.steerToTarget(avoidancePoint, topSpeed, maxForce * avoidStrength, horzOnly = horzOnly)
// }
// } else {
// obsCorrectDir = 0F
// }
//
// // accumulte forces
// // TODO: steertoTarget also checks stuff like this. Should that be different? The forces could compound here
// val accumForce = aheadForce.scale(0.5).add(avoidancForce.scale(1.0))
// var finalForce = if( avoidancForce == Vec3.ZERO) aheadForce
// else avoidancForce
//
// prevForce?.let { finalForce = it.lerp(finalForce, 0.1) }
// prevForce = finalForce
//
// pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(finalForce)
//
// // Must be called to make sure we have complete control over our entities velocity.
// mob.speed = 0f
// mob.setZza(0f)
// mob.setXxa(0f)
// mob.setDiscardFriction(true)
// pokemonEntity.orientEntityToTravel(1.0f)
// pokemonEntity.setFlying(false)
//
// drawLines.add(EntityDebugLine(forwardVec))
// if (drawLines.isNotEmpty()) {
// sendPacketToTrackingPlayers(pokemonEntity, ClientboundUpdateObsAvoidPacket(pokemonEntity.id, drawLines.toList()))
// drawLines.clear()
// }
steerSpeed = gatherTopSpeed(pokemonEntity)
val force = steerArbitrator.calculate(debug = true)
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(force)
mob.speed = 0f
mob.setZza(0f)
mob.setXxa(0f)
mob.setDiscardFriction(true)
pokemonEntity.orientEntityToTravel(1.0f)
} else if (operation == Operation.STRAFE) {
if (operation == Operation.STRAFE) {
var movingDistanceTotal = Mth.sqrt(strafeForwards * strafeForwards + strafeRight * strafeRight)
if (movingDistanceTotal < 1.0f) {
movingDistanceTotal = 1.0f
@@ -346,14 +161,10 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
val horizontalDistanceFromTarget = xDist * xDist + zDist * zDist
val closeHorizontally = horizontalDistanceFromTarget < VERY_CLOSE
if (!closeHorizontally) {
// NEW
pokemonEntity.orientEntityToTravel(1.0f)
// OLD
// val angleToTarget = Mth.atan2(zDist, xDist).toDegrees() - 90.0f
// val currentMovingAngle = mob.yRot
// val steppedAngle = Mth.approachDegrees(currentMovingAngle, angleToTarget, 100 * mediumSpeed)
// mob.yRot = steppedAngle
val angleToTarget = Mth.atan2(zDist, xDist).toDegrees() - 90.0f
val currentMovingAngle = mob.yRot
val steppedAngle = Mth.approachDegrees(currentMovingAngle, angleToTarget, 100 * mediumSpeed)
mob.yRot = steppedAngle
}
val (inWater, inLava) = mob.level().getWaterAndLavaIn(mob.boundingBox)
@@ -380,101 +191,15 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
val scale = min(adjustedSpeed.toDouble(), fullDistance.length())
val maxForce = 0.02 // 0.02
// Gather the point to be steered to
val nav = pokemonEntity.navigation
nav.pathFollowTarget?.let { rt ->
wantedX = rt.x
wantedZ = rt.z
wantedY = rt.y
}
// + 0.05 for dealing with swimming out of water, they otherwise get stuck on the lip
val steerForce = pokemonEntity.steerToTarget(Vec3(wantedX, refine(wantedY + 0.05), wantedZ), scale, maxForce)
mob.deltaMovement = mob.deltaMovement.add(steerForce)
//mob.deltaMovement = direction.scale(scale)
mob.deltaMovement = direction.scale(scale)
xDist = fullDistance.x
zDist = fullDistance.z
yDist = fullDistance.y
} else {
// division is to slow the speed down a bit so they don't overshoot when they get there.
var forwardSpeed = adjustedSpeed
var forceDiv = 1 / 5.0 // Portion of max speed that force can apply every tick
var minForce = 0.02 // If its not at least this it breaks quite a few things. looking at you snorlax
val finalGoal: BlockPos? = pokemonEntity.navigation.path?.target
val distanceToFinalGoal = finalGoal?.let {
pokemonEntity.position().distanceTo(it.center).toFloat()
} ?: 0.0f
if (distanceToFinalGoal > 8f) { //TODO: scale this to hitbox size
pokemonEntity.isPokemonSprinting = true
forwardSpeed *= 1.4f
forceDiv = 1 / 10.0
minForce *= 1.0 //TODO: figure out what to actually do for this
} else {
pokemonEntity.isPokemonSprinting = false
}
// New way
val blockFriction = mob.level()
.getBlockState(mob.getBlockPosBelowThatAffectsMyMovement())
.block.getFriction()
val frictionInfluencedSpeed = if (mob.onGround()) {
forwardSpeed * (0.21600002f / (blockFriction * blockFriction * blockFriction))
} else {
0.02f // getFlyingSpeed() default for non-player controlled. Also hopefully our checks above this caught this case
}
val baseForce = (forwardSpeed * 0.98) * frictionInfluencedSpeed
// We find where the equilibrium between vanilla friction and the input force usually is to get a topSpeed for this mon.
// Could be replaced in the future with direct topSpeed calculations in the pokemon species form
val frictionAppliedAfter = blockFriction * 0.91
val topSpeed = baseForce / (1 - frictionAppliedAfter)
val currSpeed = pokemonEntity.deltaMovement.length()
//TODO: is this needed?
// if (!pokemonEntity.isPokemonSprinting && currSpeed > topSpeed) { // TODO: this might mess up some stuff like tnt pushing mobs around
// pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.normalize().scale(lerp(currSpeed, topSpeed, 0.1))
// }
// Get a force that looks natural
val maxForce = minForce //max(baseForce * forceDiv, minForce)
// Gather the point to be steered to
val nav = pokemonEntity.navigation
nav.pathFollowTarget?.let { rt ->
wantedX = rt.x
wantedZ = rt.z
wantedY = rt.y
}
val steerForce = pokemonEntity.steerToTarget(
Vec3(wantedX, wantedY, wantedZ),
topSpeed, // Is never reached as minecraft relies on top speed being obtained when force=friction
maxForce,
horzOnly = true
)
// If this happens a lot then we have issues
val mdt = LivingEntity.MIN_MOVEMENT_DISTANCE
if ( abs(steerForce.x) < mdt || abs(steerForce.y) < mdt || abs(steerForce.z) < mdt) {
//Cobblemon.LOGGER.info("INFO: Steer Force dimension smaller than minimum movement distance value") //TODO: figure this out
}
pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(steerForce)
//pokemonEntity.deltaMovement = pokemonEntity.deltaMovement.add(Vec3(0.0103766, 0.0, 0.0))
mob.speed = 0f
mob.setZza(0f)
mob.setXxa(0f)
mob.setDiscardFriction(true)
// Old way
// mob.speed = forwardSpeed
val forwardSpeed = min(adjustedSpeed, max(horizontalDistanceFromTarget.toFloat() / 2, 0.15F))
mob.speed = forwardSpeed
}
if (!verticalHandled) {
@@ -555,41 +280,6 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
}
}
fun gatherTopSpeed( pokemonEntity: PokemonEntity): Double {
val behaviour = pokemonEntity.behaviour
val mediumSpeed = runtime.resolveFloat(if (pokemonEntity.getCurrentPoseType() in setOf(PoseType.FLY, PoseType.HOVER)) {
behaviour.moving.fly.flySpeedHorizontal
} else if (pokemonEntity.isEyeInFluid(FluidTags.WATER) || pokemonEntity.isEyeInFluid(FluidTags.LAVA)) {
behaviour.moving.swim.swimSpeed
} else {
behaviour.moving.walk.walkSpeed
}) * 2.5F //TODO: idk why this is 2.5 but I think we're stuck with it
val baseSpeed = mob.getAttributeValue(Attributes.MOVEMENT_SPEED).toFloat() * 0.4f //TODO: does this ever need to not be hardcoded?
val adjustedSpeed = baseSpeed * mediumSpeed
val forwardSpeed = adjustedSpeed
val blockFriction = mob.level()
.getBlockState(mob.getBlockPosBelowThatAffectsMyMovement())
.block.getFriction()
val frictionInfluencedSpeed = if (mob.onGround()) {
forwardSpeed * (0.21600002f / (blockFriction * blockFriction * blockFriction))
} else {
0.02f // getFlyingSpeed() default for non-player controlled
}
// Force applied every tick through the usual vanilla route
val baseForce = (forwardSpeed * 0.98) * frictionInfluencedSpeed
// We find where the equilibrium between vanilla friction and the input force usually is to get a topSpeed for this mon.
// Could be replaced in the future with direct topSpeed calculations in the pokemon species form
val frictionAppliedAfter = blockFriction * 0.91
val topSpeed = baseForce / (1 - frictionAppliedAfter)
return topSpeed
}
/*
* Returns the ideal water level y position of a given pokemon during battle.
* This is separate for the eye height check and is dependent on if the pokemon is rafted or swimming.
@@ -1,56 +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.entity.pokemon.ai.sensors
import com.cobblemon.mod.common.CobblemonMemories
import com.google.common.collect.ImmutableSet
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.Sensor
import net.minecraft.world.item.Items
import net.minecraft.world.entity.player.Player
class PlayerDebuggingSensor : Sensor<LivingEntity>(SCAN_INTERVAL) {
override fun doTick(level: ServerLevel, entity: LivingEntity) {
var diamondHolder: LivingEntity? = null
diamondHolder = entity.brain.getMemory(CobblemonMemories.DIAMOND_DEBUGGER).orElse(null)?.let {
if(it.mainHandItem.`is`(Items.DIAMOND)) {
it
} else {
null
}
}
if (diamondHolder == null) {
val nearEntities = entity.brain.getMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES).orElse(mutableListOf())
diamondHolder = nearEntities?.find { entity ->
entity.mainHandItem.`is`(Items.DIAMOND)
}
}
if (diamondHolder != null && diamondHolder is Player) {
entity.brain.setMemory(CobblemonMemories.DIAMOND_DEBUGGER, diamondHolder)
} else {
entity.brain.eraseMemory(CobblemonMemories.DIAMOND_DEBUGGER)
}
}
override fun requires(): Set<MemoryModuleType<*>> {
return setOf(
CobblemonMemories.DIAMOND_DEBUGGER,
MemoryModuleType.NEAREST_LIVING_ENTITIES
)
}
companion object {
const val SCAN_INTERVAL = 10
}
}
@@ -1,40 +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.entity.pokemon.ai.tasks;
//
//import com.cobblemon.mod.common.CobblemonMemories
//import com.cobblemon.mod.common.api.pokemon.status.Statuses
//import com.cobblemon.mod.common.api.storage.party.PartyStore
//import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
//import net.minecraft.world.entity.ai.behavior.OneShot
//import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
//import net.minecraft.world.entity.ai.behavior.declarative.Trigger
//import net.minecraft.world.entity.ai.memory.MemoryModuleType
//
//object BoidsTask {
//fun create(): OneShot<PokemonEntity> {
// return BehaviorBuilder.create {
// it.group(
// it.absent(CobblemonMemories.POKEMON_DROWSY)
// ).apply(it) { _ ->
// Trigger { world, entity, _ ->
// if (entity.pokemon.status?.status == Statuses.SLEEP && entity.pokemon.storeCoordinates.get()?.store !is PartyStore) {
// entity.pokemon.status = null
// entity.brain.eraseMemory(CobblemonMemories.POKEMON_SLEEPING)
// entity.brain.useDefaultActivity()
// return@Trigger true
// } else {
// return@Trigger false
// }
// }
// }
// }
//}
//}
@@ -1,111 +0,0 @@
package com.cobblemon.mod.common.entity.pokemon.extensions
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.math.geometry.toDegrees
import net.minecraft.util.Mth
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.phys.Vec3
import kotlin.math.abs
import kotlin.math.min
import kotlin.math.sign
/*************************************************************************************************************
Steering to Target
Detailed in: https://www.red3d.com/cwr/steer/gdc99/
*************************************************************************************************************/
fun PokemonEntity.steerToTarget(
targetPos: Vec3,
maxSpeed: Double,
maxForce: Double,
arrivalRange: Double? = null,
horzOnly: Boolean = false
): Vec3 {
val cPos = if (horzOnly) Vec3(this.position().x, 0.0, this.position().z) else this.position()
val tPos = if (horzOnly) Vec3(targetPos.x, 0.0, targetPos.z) else targetPos
// Ensure we can't have a negative range here
val absArrivalRange = arrivalRange?.let { abs(arrivalRange) }
// Calculate the vector from the pokemons current position to the
// target position. Set its desired magnitude to max speed or a
// portion of it if within the arrivalRange
val toTargetVec = tPos.subtract(cPos)
val distToTarget = toTargetVec.length()
val desiredSpeed = if (absArrivalRange != null && distToTarget < absArrivalRange) (distToTarget/absArrivalRange) * maxSpeed else maxSpeed
val desiredVec = toTargetVec.normalize().scale(desiredSpeed)
var steer = if (horzOnly) desiredVec.subtract(Vec3(this.deltaMovement.x, 0.0, this.deltaMovement.z))
else desiredVec.subtract(this.deltaMovement)
if (steer.length() > maxForce) {
steer = steer.normalize().scale(maxForce)
}
return steer
}
/*************************************************************************************************************
Steering Target Avoidance
Detailed in: https://www.red3d.com/cwr/steer/gdc99/
*************************************************************************************************************/
fun PokemonEntity.avoidTarget(
targetPos: Vec3,
maxSpeed: Double,
maxForce: Double,
avoidanceRange: Double? = null
): Vec3 {
// Calculate the vector from the targets current position to the
// pokemon position. Set its desired magnitude to max speed scaled
// linearly from 1.0 when right next to the target and 0.0 when on the
// very edge of the avoidance Range
var fromTargetVec = this.position().subtract(targetPos)
// Calculate distance to the target
val distToTarget = fromTargetVec.length()
if (distToTarget < 1.0E-4) {fromTargetVec = Vec3(0.0, 1.0, 0.0)} // Ensure the avoidance vector can't be ZERO
// Return no force otherwise a desired vector will be calculated that slows the velocity.
if (avoidanceRange != null && distToTarget >= avoidanceRange) return Vec3.ZERO
// Scale the avoidance force linearly
val desiredSpeed = when {
avoidanceRange == null -> maxSpeed // If no avoidance range then just always flee as fast as you can
avoidanceRange == 0.0 -> maxSpeed // Avoid weird divide by zero nonsense
distToTarget < avoidanceRange -> (1.0 - (distToTarget / avoidanceRange)) * maxSpeed
else -> 0.0
}
//TODO: determine if this should be scaled by distance. Probably not
val desiredVec = fromTargetVec.normalize() //.scale(desiredSpeed)
// Steer the pokemon towards the desired vector
var steer = desiredVec.subtract(this.deltaMovement)
if (steer.length() > maxForce) {
steer = steer.normalize().scale(maxForce)
}
return steer
}
/*************************************************************************************************************
Lerp the mobs yRot to its direction of travel
*************************************************************************************************************/
fun PokemonEntity.orientEntityToTravel(k: Float = 1.0f) {
val interpAmount = k.coerceIn(0.0f, 1.0f) //TODO: This probably shouldn't be a lerp like this.
if (this.deltaMovement.length() < 0.01) return //LivingEntity.MIN_MOVEMENT_DISTANCE) return
// Ensure the entity is facing the direction it is moving in both pitch and yaw
val normVec = this.deltaMovement.normalize()
val targetAngle = Mth.atan2(normVec.z, normVec.x).toDegrees() - 90.0f
val currAngle = this.yRot
val angleDiff = Mth.wrapDegrees(targetAngle - currAngle)
val maxPerTickRotation = 30.0f // set really high to ignore for now 15.0f // TODO: is something like this needed or should it be a clientside spring or something?
val effRot = min(abs(angleDiff), maxPerTickRotation) * sign(angleDiff)
this.yRot = currAngle + (effRot * interpAmount)
//entity.xRot = asin(normVec.y.toFloat()).toDegrees()
}
@@ -1,49 +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.net.messages.client.debug
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.client.render.debug.EntityDebugLine
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeCollection
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
/**
* Packet sent to the client to update the obstacle avoidance lines to be rendered
* while debugging
*
* @author Jackson
* @since September 15th, 2025
*/
class ClientboundUpdateObsAvoidPacket(val entityId: Int, val lines: List<EntityDebugLine>) : NetworkPacket<ClientboundUpdateObsAvoidPacket> {
override val id: ResourceLocation = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeInt(entityId)
buffer.writeCollection(lines) { _, linePair ->
linePair.encode(buffer)
}
}
companion object {
val ID = cobblemonResource("obstacle_avoidance_lines")
fun decode(buffer: RegistryFriendlyByteBuf): ClientboundUpdateObsAvoidPacket {
val entityId = buffer.readInt()
val lines = buffer.readList { buf ->
EntityDebugLine.decode(buf as RegistryFriendlyByteBuf)
}
return ClientboundUpdateObsAvoidPacket(entityId, lines)
}
}
}
@@ -77,8 +77,7 @@ object PokemonBrain {
CobblemonSensors.NEARBY_GROWABLE_CROPS,
CobblemonSensors.NEARBY_BEE_HIVE,
CobblemonSensors.NEARBY_FLOWER,
CobblemonSensors.NEARBY_SWEET_BERRY_BUSH,
CobblemonSensors.PLAYER_DEBUGGING
CobblemonSensors.NEARBY_SWEET_BERRY_BUSH
// CobblemonSensors.BATTLING_POKEMON,
// CobblemonSensors.NPC_BATTLING
@@ -180,7 +179,6 @@ object PokemonBrain {
MemoryModuleType.HURT_BY_ENTITY,
MemoryModuleType.NEAREST_PLAYERS,
MemoryModuleType.NEAREST_VISIBLE_PLAYER,
MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER,
MemoryModuleType.ANGRY_AT,
MemoryModuleType.ATTACK_COOLING_DOWN,
CobblemonMemories.POKEMON_DROWSY,
@@ -203,8 +201,7 @@ object PokemonBrain {
CobblemonMemories.HERD_LEADER,
CobblemonMemories.HERD_SIZE,
CobblemonMemories.ATTACK_TARGET_DATA,
CobblemonMemories.NEARBY_SWEET_BERRY_BUSH,
CobblemonMemories.DIAMOND_DEBUGGER
CobblemonMemories.NEARBY_SWEET_BERRY_BUSH
)
private fun coreTasks(pokemon: Pokemon) = buildList<Pair<Int, BehaviorControl<in PokemonEntity>>> {
@@ -200,10 +200,6 @@
{
"condition": "q.is_holding_item",
"animation": "q.bedrock('charizard', 'hold_item')"
},
{
"condition": "!q.is_ridden",
"animation": "q.pitch_tilt('body', 0.8)"
}
],
"quirks": [
@@ -221,10 +217,9 @@
"q.look('neck4', 0.35, 0.35, 5, -5, 15, -15)",
"q.look('head', 0.4, 0.25, 5, -5, 10, -10)",
"q.bedrock('charizard', 'air_fly')",
"q.bedrock('charizard', 'ride_air_fly')",
{
"condition": "!q.is_ridden",
"animation": "q.pitch_tilt('body', 0.8)"
"condition": "q.is_ridden",
"animation": "q.bedrock('charizard', 'ride_air_fly')"
},
{
"condition": "q.is_holding_item",
@@ -65,9 +65,7 @@
},
"hover": {
"poseTypes": ["HOVER"],
"animations": [
"q.look('neck')", "q.bedrock('pidgeot', 'air_idle')"
],
"animations": ["q.look('neck')", "q.bedrock('pidgeot', 'air_idle')"],
"transformedParts": [
{
"part": "wing_open_left",
@@ -93,14 +91,7 @@
"fly": {
"poseTypes": ["FLY"],
"condition": "!q.is_gliding",
"animations": [
"q.look('neck')",
"q.bedrock('pidgeot', 'air_idle')",
{
"condition": "!q.is_ridden",
"animation": "q.pitch_tilt('body', 0.8)"
}
],
"animations": ["q.look('neck')", "q.bedrock('pidgeot', 'air_idle')"],
"transformedParts": [
{
"part": "wing_open_left",
@@ -97,7 +97,7 @@
"item.cobblemon.npc_editor": "NPC's Trainer Card",
"item.cobblemon.link_cable": "Link Cable",
"item.cobblemon.link_cable.tooltip": "Evolves Pokémon that require trading",
"item.cobblemon.link_cable.tooltip": "Evolves pokemon that require trading",
"item.cobblemon.dragon_scale": "Dragon Scale",
"item.cobblemon.dragon_scale.tooltip": "Evolves Seadra into Kingdra when held while trading",
"item.cobblemon.kings_rock": "Kings Rock",
@@ -423,7 +423,7 @@
"item.cobblemon.razor_fang.tooltip_1": "When the holder successfully inflicts damage, the target may also flinch",
"item.cobblemon.razor_fang.tooltip_2": "Evolves Gligar into Gliscor when held while leveling up during the night",
"item.cobblemon.red_card": "Red Card",
"item.cobblemon.red_card.tooltip_1": "Pokémon that damage the holder are forced to switch out",
"item.cobblemon.red_card.tooltip_1": "Pokemon that damage the holder are forced to switch out",
"item.cobblemon.red_card.tooltip_2": "Consumed after use",
"item.cobblemon.ring_target": "Ring Target",
"item.cobblemon.ring_target.tooltip": "The holder's type immunities are removed",
@@ -489,7 +489,7 @@
"item.cobblemon.white_herb.tooltip_1": "Restores any lowered stat in battle",
"item.cobblemon.white_herb.tooltip_2": "Consumed after use",
"item.cobblemon.bright_powder": "Bright Powder",
"item.cobblemon.bright_powder.tooltip": "Reduces the accuracy of enemy Pokémon's moves by 10%",
"item.cobblemon.bright_powder.tooltip": "Reduces the accuracy of enemy pokemon's moves by 10%",
"item.cobblemon.metal_powder": "Metal Powder",
"item.cobblemon.metal_powder.tooltip": "Raises an untransformed Ditto's Defense and Sp. Def by 50%",
"item.cobblemon.quick_powder": "Quick Powder",
@@ -2122,7 +2122,6 @@
"cobblemon.ui.status.psn": "PSN",
"cobblemon.ui.status.slp": "SLP",
"cobblemon.ui.status.tox": "PSN",
"cobblemon.ui.exp.number": "+%1$s §oEXP",
"cobblemon.battle.ui.fight": "Fight",
"cobblemon.battle.ui.switch": "Switch",
"cobblemon.battle.ui.capture": "Catch",
@@ -2494,10 +2493,6 @@
"cobblemon.config.ui.allow_experience_from_pvp.tooltip": "Whether to allow Exp. gain from PvP battles.",
"cobblemon.config.ui.experience_share_multiplier": "Experience Share Multiplier",
"cobblemon.config.ui.experience_share_multiplier.tooltip": "Multiplier of how much of the total Exp is given to a Pokémon holding an Exp. Share.",
"cobblemon.config.ui.award_experience_to_fainted_pokemon": "Award Exp. to Fainted Pokémon",
"cobblemon.config.ui.award_experience_to_fainted_pokemon.tooltip": "Whether fainted Pokémon receive Exp. for opponents they helped defeat before fainting.",
"cobblemon.config.ui.award_experience_on_battle_loss": "Award Exp. on Battle Loss",
"cobblemon.config.ui.award_experience_on_battle_loss.tooltip": "Whether Pokémon receive Exp. for opponents they defeated even if the battle is lost. Requires 'Award Exp. to Fainted Pokémon' to be enabled for fainted Pokémon to benefit.",
"cobblemon.config.ui.lucky_egg_multiplier": "Lucky Egg Multiplier",
"cobblemon.config.ui.lucky_egg_multiplier.tooltip": "Multiplier of how much of the total Exp is given to a Pokémon holding a Lucky Egg.",
"cobblemon.config.ui.allow_spectating": "Allow Spectating",
@@ -2608,7 +2603,7 @@
"cobblemon.config.ui.summary_profile_animations.always_animate.tooltip": "Entire party animates unless fainted",
"cobblemon.config.ui.third_person_view_bobbing": "Third Person View Bobbing",
"cobblemon.config.ui.third_person_view_bobbing.tooltip": "If true then use default Minecraft behavior to follow directly behind the player's head. If false then follow a fixed offset from the Pokémon.",
"cobblemon.config.ui.third_person_view_bobbing.tooltip": "If true then use default Minecraft behavior to follow directly behind the player's head. If false then follow a fixed offset from the pokemon.",
"cobblemon.config.ui.invert_pitch": "Invert Pitch",
"cobblemon.config.ui.invert_pitch.tooltip": "Invert the direction for pitch (up and down).",
"cobblemon.config.ui.invert_yaw": "Invert Yaw",
@@ -3408,7 +3403,6 @@
"cobblemon.starterselection.category.galar": "Galar",
"cobblemon.starterselection.category.hisui_bias": "Hisui",
"cobblemon.starterselection.category.paldea": "Paldea",
"cobblemon.starterselection.category.special": "Special",
"cobblemon.stat.hp.name": "HP",
"cobblemon.stat.attack.name": "Attack",
@@ -3897,9 +3891,6 @@
"cobblemon.behaviour.pokemon_bee.name": "Pollinates Flowers",
"cobblemon.behaviour.pokemon_bee.desc": "Pollinates flowers and adds honey to hives and Saccharine tree leaves.",
"cobblemon.behaviour.pokemon_boids.name": "Boids",
"cobblemon.behaviour.pokemon_boids.desc": "Boids Around.",
"cobblemon.behaviour.pokemon_picks_up_items.name": "Picks Up Items",
"cobblemon.behaviour.pokemon_picks_up_items.desc": "The Pokémon will pick up items that it cares about.",
@@ -161,7 +161,7 @@
"sounds": [ { "name": "cobblemon:item/pokedex/pokedex_scan_zoom_increment", "volume": 0.7 } ]
},
"evolution.notification": {
"sounds": [ { "name": "cobblemon:evolution/evolution_notification", "volume": 1.0 } ]
"sounds": [ { "name": "cobblemon:evolution/evolution_notification", "volume": 0.7 } ]
},
"evolution.full": {
"sounds": [ { "name": "cobblemon:evolution/evolution_full", "volume": 0.9 } ]
@@ -173,7 +173,7 @@
"sounds": [ { "name": "cobblemon:gui/levelup_start", "volume": 0.15 } ]
},
"gui.levelup": {
"sounds": [ { "name": "cobblemon:gui/levelup", "volume": 0.55 } ]
"sounds": [ { "name": "cobblemon:gui/levelup", "volume": 0.65 } ]
},
"gui.click": {
"sounds": [ "cobblemon:gui/click" ]
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 785 B

Loaded 100 of 384 files, more files were not shown because too many files have changed in this diff. Show more