Compare commits

...
Author SHA1 Message Date
Konoha 925f4ebed5 Isometric 2025-07-17 18:02:01 -04:00
Konoha 8b79963129 Lighting 2025-07-17 16:27:03 -04:00
Konoha 3a533a6d9c Aesthetics 2025-07-17 13:20:03 -04:00
Konoha 0dbcf2539b Merge branch 'implement_pokemon' into pokemodel_items 2025-07-17 10:44:09 -04:00
Konoha 6d9f865099 Merge branch 'implement_pokemon' into pokemodel_items 2025-07-16 21:23:20 -04:00
Konoha 5d2fa8427a Merge branch 'implement_pokemon' into pokemodel_items 2025-07-16 18:19:36 -04:00
Konoha 8f8b2627f7 Backshots 2025-07-11 21:23:23 -04:00
Konoha 4ad0686b03 Creative Tab 2025-07-11 16:45:49 -04:00
Konoha a56ffe1742 Merge remote-tracking branch 'origin/main' 2025-07-11 11:04:14 -04:00
Hiroku 6d1570302d Merge branch 'unbreak-servers' into 'main'
Random bullshit go!

See merge request cable-mc/cobblemon!1736
2025-07-09 11:35:21 +00:00
Nadja Reitzenstein 811e9d3352 Don't return items after battles that weren't actually used. 2025-07-09 12:48:41 +02:00
Nadja Reitzenstein e610aa18d7 Clean up imports and other assorted compiler warnings 2025-07-09 00:56:02 +02:00
Nadja Reitzenstein 42ecd3e813 Replace if-creative-then-stack.shrink with the proper stack.consume method.
This is both nicer to read and also reduces our code by a few lines. Additionally, this replaces all player.isCreative checks with the more appropriate player.hasInfiniteMaterials one.
2025-07-09 00:44:33 +02:00
Nadja Reitzenstein 1299b8fee8 Fix an ExceptionInInitializer error on specifically dedicated servers. 2025-07-08 23:53:35 +02:00
Landon a12cf17cfa Merge branch 'hotfix-infinite-falldamage' into 'main'
Correctly reset a ridden Pokémon's fall damage server-side

See merge request cable-mc/cobblemon!1735
2025-07-08 21:52:22 +00:00
Nadja Reitzenstein 74faca60f2 Correctly reset a ridden Pokémon's fall damage server-side 2025-07-08 23:12:15 +02:00
Landon 6420176787 Merge branch 'change-a-few-numbers-nothing-to-see-here' into 'main'
Change a few numbers here and there, nothing to see here :)

See merge request cable-mc/cobblemon!1734
2025-07-08 20:37:39 +00:00
Nadja Reitzenstein 6ee81fe2ab Fix a fun build error 2025-07-08 22:24:37 +02:00
Nadja Reitzenstein 96f4f988f8 Update dependencies chore 2025-07-08 21:31:56 +02:00
Hiroku 4ccfbbcb37 Merge branch '1622-fix-battle-screen-closing' into 'main'
Fix battle GUI not closing

Closes #1622

See merge request cable-mc/cobblemon!1723
2025-07-08 14:02:38 +00:00
Hiroku ed0aa83013 Merge branch 'light' into 'main'
Update block lighting + lambdynamiclights compat items

See merge request cable-mc/cobblemon!1731
2025-07-08 12:42:22 +00:00
Hiroku b94394f8d1 Merge branch 'forever-rock' into 'main'
suppress evolution notification and hide evolve button if holding everstone

See merge request cable-mc/cobblemon!1732
2025-07-08 12:39:45 +00:00
Hiroku b16687c132 Merge branch 'evolution-concurrent-hotpatch' into 'main'
Make Evolution more resilient against concurrent modification exceptions.

Closes #1536

See merge request cable-mc/cobblemon!1725
2025-07-08 10:31:50 +00:00
Hiroku 56767b3e31 Merge branch 'jet-momentum-damage' into 'main'
Jet behaviour momentum damage logic

Closes #1555

See merge request cable-mc/cobblemon!1715
2025-07-08 10:31:05 +00:00
AramandHiroku 67eb3e1046 Jet behaviour momentum damage logic 2025-07-08 10:31:04 +00:00
Test 952ea8d3b7 suppress evolution notification and hides evolve button in summary interface if Pokémon is holding Everstone 2025-07-07 22:27:37 -04:00
Test cc764ff9db add farmland to water plantable for hearty 2025-07-07 18:51:22 -04:00
Nadja Reitzenstein 2e1f8af700 Make Evolution more resilient against concurrent modification exceptions.
BenchedMoves is quite vulnerable to concurrent modifications as it does no internal locking. The code changed in this commit showcases that issue extremely well: As `pokemon.benchedMoves` was updated one-by-one and each update send a separate BenchedMovesUpdatePacket which would all be handled in parallel by the Client evolving a Pokémon which lears a bunch of moves on evolution was an almost sure-fire way to crash the game.

This *isn't a fix* for that! It's merely a hotpatch to make sure this common a crash doesn't sneak itself into the next release.

Fixes: #1536
2025-07-07 18:16:24 +02:00
Test 6c6a8e4679 indents 2025-07-06 16:12:28 -04:00
Test 9e9a22eb14 Update block lighting, add lambdynamiclights support for items 2025-07-06 16:08:14 -04:00
Test 32bfaf152d +vibrance galarica, fix hearty stage + allow planting on dry farmland 2025-07-06 04:59:25 -04:00
Hiroku d1b947b264 Merge branch 'blox' into 'main'
update sacch/crops/blocks, consolidate POI registration

See merge request cable-mc/cobblemon!1729
2025-07-06 05:29:46 +00:00
Test 6122fb6107 disallow honey on leaves if waterlogged 2025-07-06 00:49:29 -04:00
Paul 14c7ee3216 Added PokedexManager.obtain as a replacement for catch (java interop) 2025-07-06 14:04:59 +10:00
Hiroku 1a00ae7fb8 Merge branch 'particle-fix' into 'main'
Fixed rotation of locators relative to entities.

Closes #1573

See merge request cable-mc/cobblemon!1726
2025-07-06 01:45:57 +00:00
JPAKx4 36b3cbe3b8 Fix Formatting. 2025-07-05 20:03:18 -05:00
JPAKx4 49686a1670 Merge remote-tracking branch 'origin/particle-fix' into particle-fix 2025-07-05 20:00:53 -05:00
JPAKx4andJordan 2354888a73 Cleanup some now unused code and comment out some debug code. 2025-07-06 00:09:33 +00:00
JPAKx4andJordan f64065d54f this suckssssss 2025-07-06 00:09:33 +00:00
JPAKandJordan 005ab0ca74 Locator Debug Code 2025-07-06 00:09:33 +00:00
JPAKandJordan c13307e931 temp commit 2025-07-06 00:09:33 +00:00
JPAKx4andJordan bd21a6e1ca Fixed the root locator losing rotation and removed unnecessary scaling. 2025-07-06 00:09:33 +00:00
JPAKx4 94ea15b9c5 Cleanup some now unused code and comment out some debug code. 2025-07-05 19:08:41 -05:00
Test bc6c9def56 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into blox 2025-07-05 17:50:12 -04:00
Test 9ca6a2e461 fix block drop, prevent smearing honey in water, +log cosmetics 2025-07-05 15:26:09 -04:00
Test f7560a12ad update sacch/crops/blocks, consolidate POI registration 2025-07-05 04:12:58 -04:00
Test 8bc1767917 Merge branch 'we-must-defend-our-way-of-life' into 'main'
Pokemon can be made to hunt from the pasture block

See merge request cable-mc/cobblemon!1728
2025-07-05 06:45:27 +00:00
Test 8b29d3a533 Merge branch '1603-out-of-sync-guis' into 'main'
Resolve "Staying on party screen while a Pokémon evolves causes temporary weirdness."

Closes #1603

See merge request cable-mc/cobblemon!1717
2025-07-05 06:44:33 +00:00
JPAKx4 de1248b97e this suckssssss 2025-07-04 21:36:44 -05:00
Paul a654225ed5 Improve handling of pasture conflict behaviour flag 2025-07-05 11:31:29 +10:00
JPAK 2d18113e27 Locator Debug Code 2025-07-04 20:21:57 -05:00
JPAK cdadc6fa67 temp commit 2025-07-04 20:21:40 -05:00
JPAKx4 ff7ef1b67e Merge remote-tracking branch 'origin/particle-fix' into particle-fix 2025-07-04 16:45:34 -05:00
JPAKx4 d91c819700 Fixed the root locator losing rotation and removed unnecessary scaling. 2025-07-04 16:45:19 -05:00
Josh 259e1d05cb Changing nickname no longer causes ModelWidget state to updated 2025-07-04 04:35:05 -04:00
Paul 549b88a4c2 Removed unnecessary thing 2025-07-04 14:43:24 +10:00
Hiroku 68b60e7d50 Merge branch 'wheel' into 'main'
Tetragon ➜ Octagon

See merge request cable-mc/cobblemon!1727
2025-07-04 03:33:42 +00:00
Test a7787707f2 changelog 2025-07-03 22:52:50 -04:00
Test 539097e681 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into wheel
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/interact/wheel/InteractWheelGUI.kt
2025-07-03 22:39:06 -04:00
Test 8b70a4124d Interact Tetragon ➜ Interact Octagon 2025-07-03 22:38:49 -04:00
Test 7e8b000311 Merge branch 'bugfix/fix-interact-wheel-issues' into 'main'
Fix minor bugs related to the Pokemon interaction wheel

See merge request cable-mc/cobblemon!1722
2025-07-04 02:30:58 +00:00
StarliteHeartandTest 00c86b89cb Fix minor bugs related to the Pokemon interaction wheel 2025-07-04 02:30:57 +00:00
JPAKx4 b2c9d96829 Fixed the root locator losing rotation. 2025-07-03 20:35:49 -05:00
Hiroku 8ea5ea6804 changelog [skip-ci] 2025-07-03 11:15:23 +00:00
Hiroku 1305e8a11d Merge branch 'level-rng-fixes' into 'main'
Rewrite potentially sketchy uses of randomness.

Closes #1560

See merge request cable-mc/cobblemon!1724
2025-07-03 11:14:09 +00:00
Nadja Reitzenstein 909cd8a6eb Adds the Concurrent Chunk Management Engine (C2ME) to runtime dependencies.
While no code relies on any internals or even features of C2ME that mod increases performance massively, especially on servers. This means it's reasonably often used and compatability with it is a reasonable goal to have.

Additionally, it helps to detect multithreading bugs by distributing workload over more threads than vanilla and thus making it much more likely to hit those bugs.
2025-07-03 12:53:29 +02:00
Nadja Reitzenstein d60abdc940 Rewrite potentially sketchy uses of randomness.
Using the random source stored in `Level` from a different thread can lead to hard-to-debug ConcurrentAccessExceptions. A common source for these problems is using level randomness in networking code such as synced data.

This commit rewrites three potentially sketchy usages of level randomness into a form that I think is safe from this particular problem.

Fixes: #1560
2025-07-03 12:53:29 +02:00
Paul ec8e6f58c8 Merge remote-tracking branch 'origin/we-must-defend-our-way-of-life' into we-must-defend-our-way-of-life 2025-07-03 18:35:15 +10:00
Paul 12967e4813 Bits of AI cleanup and fixed non-look pokemon still looking 2025-07-03 18:35:08 +10:00
Paul d754cc69fe Merge remote-tracking branch 'origin/main' into we-must-defend-our-way-of-life 2025-07-03 18:29:10 +10:00
Charzard4261 a2b54643fe Remove fake PartySendBinding press on BattleGUI close 2025-07-03 00:09:12 +01:00
Test 896c195dd9 reverse pc scroll direction 2025-07-02 18:59:47 -04:00
Landon 206bfacba0 Merge branch 'multi-seat-mounts' into 'main'
Multi seat mounts

See merge request cable-mc/cobblemon!1721
2025-07-02 18:07:40 +00:00
Landon Wills b6ffbd1ed8 Update licenses 2025-07-02 13:55:11 -04:00
Landon Wills 829900fb58 Prevent seat shifts when passengers dismount 2025-07-02 02:13:26 -04:00
Test be3066f7b2 rm commented 2025-07-02 00:07:57 -04:00
Test fb56ab5865 update pc, pasture slots 2025-07-01 23:40:54 -04:00
Test a3f02a8a7c Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into we-must-defend-our-way-of-life 2025-07-01 19:42:09 -04:00
Paul 6c2757b94b Fixed issues with sending out pokes 2025-07-01 21:33:05 +10:00
Test 139ef56fdf account for users putting in negative numbers for control overlay duration 2025-06-30 23:32:22 +00:00
Paul d3e473ff85 Merge remote-tracking branch 'origin/main' into we-must-defend-our-way-of-life 2025-06-30 20:05:40 +10:00
Paul fdebc5987e Merge remote-tracking branch 'origin/main' 2025-06-30 19:53:09 +10:00
Paul caeeb756fe Fixed crash with several pokemon due to particle locators not being there at the time effects played 2025-06-30 19:52:47 +10:00
Polymeta 67b5e5c6a8 fixes for scanner overlay and display case block
Signed-off-by: Polymeta <40173118+Polymeta@users.noreply.github.com>
2025-06-30 10:45:02 +01:00
Paul 720eef5e75 finalizeSpawn for PokemonEntity's 2025-06-30 16:33:04 +10:00
Landon ebc7f67655 Merge branch 'snapshot-warnings' into 'main'
Prepare for displaying a snapshot warning to users

See merge request cable-mc/cobblemon!1706
2025-06-30 06:10:47 +00:00
NickandLandon 3c508c5bd1 Prepare for displaying a snapshot warning to users 2025-06-30 06:10:46 +00:00
Landon c7052d295c Merge branch 'controls-overlay' into 'main'
Ride Controls Overlay

See merge request cable-mc/cobblemon!1720
2025-06-30 05:52:31 +00:00
Landon Wills 9193e9a372 Reduce default display second config value slightly 2025-06-30 01:07:44 -04:00
Test f6244cbe12 controls overlay 2025-06-30 00:11:35 -04:00
Paul 5743a04db7 Fixed sleeping pokemon outside of battle never waking up (DUN DUNNN) 2025-06-30 10:40:27 +10:00
Paul 439a5077c2 Merge remote-tracking branch 'origin/main' into we-must-defend-our-way-of-life
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/TaskConfig.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/ai/CombatBehaviour.kt
#	common/src/main/resources/data/cobblemon/species/generation1/charizard.json
2025-06-30 10:16:59 +10:00
Polymeta a8a028bb7a Merge branch 'more-ai' into 'main'
Lots more brain work and some fixes

See merge request cable-mc/cobblemon!1719
2025-06-29 23:12:56 +00:00
Paul 984e10a780 Prototype for behaviour scraper 2025-06-29 18:51:38 +10:00
Paul ad0571a782 lil renames and stuff 2025-06-29 18:37:59 +10:00
Paul a18581ae1c Merge remote-tracking branch 'origin/lang-updates' 2025-06-29 10:29:50 +10:00
Zack the GhastandWeblate 177ad70172 Translated using Weblate (Portuguese (Portugal))
Currently translated at 63.0% (5365 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-06-28 18:20:05 +00:00
washashu0905andWeblate 98fb731270 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 94.7% (8062 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-28 18:20:04 +00:00
阿鱼andWeblate a98dbcf267 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 87.9% (7480 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-28 18:20:02 +00:00
Konoha 62e9294c8a Merge remote-tracking branch 'origin/main' 2025-06-28 11:41:40 -04:00
Paul 314bd19dc6 Fixed clicking on combat icon in pasture block 'selecting' the entry, also licenses 2025-06-28 10:23:55 +10:00
Paul c0344f5604 Fixed entity lookup for pasture S2C packet 2025-06-28 10:09:35 +10:00
Paul 2f8a9f207c Removed unnecessary fields from cosmetic item definitions 2025-06-27 22:22:54 +10:00
Paul 8c1416514c Merge remote-tracking branch 'weblate/lang-updates' 2025-06-27 22:08:55 +10:00
washashu0905andWeblate 575c33612d Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 94.1% (8009 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-27 12:08:24 +00:00
Paul 889d193ad1 Shouldn't have vi.json, only vi_vn.json 2025-06-27 22:07:19 +10:00
Paul 57ef37099e Merge remote-tracking branch 'weblate/lang-updates' 2025-06-27 22:05:04 +10:00
Paul d7d311764d Fixed a few brain memory crashes, made herds more complicated with tiers of leaders 2025-06-27 22:04:06 +10:00
Zack the GhastandWeblate d7fb65d23b Translated using Weblate (Portuguese (Portugal))
Currently translated at 62.1% (5285 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-06-27 12:01:01 +00:00
washashu0905andWeblate 3e4449aed1 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 94.0% (7999 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-27 12:01:00 +00:00
plastered_crab 55aa50654c Safer getPokemon on pasture block 2025-06-27 03:03:54 -07:00
plastered_crab 489170cf00 DTO FAFO 2025-06-27 02:32:17 -07:00
Polymeta 930eb42e76 Merge branch '1594-sounds-while-capturing' into 'main'
Resolve "[1.7] Wing flap sounds continue to play while target is struggling inside of a pokeball."

Closes #1594

See merge request cable-mc/cobblemon!1718
2025-06-27 09:19:49 +00:00
plastered_crab 87d76e8788 Trying to get the Pokemon DTO to load on the pasture UI properly to reflect behavior flags on the entity 2025-06-27 01:55:00 -07:00
Landon Wills 6d8bf59eee Add dedicated dismount packet, clear up dismount logic, recall all pokemon on mount 2025-06-27 03:58:50 -04:00
Paul a8f431868a Merge remote-tracking branch 'origin/main' into more-ai 2025-06-27 17:26:39 +10:00
Landon Wills 0c6e355c6b Merge branch 'main' into multi-seat-mounts 2025-06-27 00:38:00 -04:00
Josh a2f6ab0ea4 Silence pokemon while in ball 2025-06-26 09:36:22 -04:00
Paul 719a56e7c3 Remove all that is unnecessary and you will come to know true peace 2025-06-26 20:52:29 +10:00
Konoha bd4397ec55 Merge remote-tracking branch 'origin/main' 2025-06-25 21:11:08 -04:00
Konoha d5e3781fc5 Merge remote-tracking branch 'origin/legacy_and_event_moves' 2025-06-25 21:10:53 -04:00
Josh 776ab05ac1 nickname widget now updates properly 2025-06-25 21:06:45 -04:00
Josh 0da5d27851 Added observer to Summary UI with clean up 2025-06-25 18:22:51 -04:00
Josh 48b28bc509 Removed observer from RenderablePokemon 2025-06-25 18:22:10 -04:00
Josh 5547326798 Updated RenderablePokemon to have an option to sync to a Pokemon so the render updates automatically 2025-06-25 14:06:39 -04:00
Josh bcf730a07f updated PokemonProperties to use swapHeldItem() rather then setting directly in order to sync client and server mons 2025-06-25 14:04:44 -04:00
washashu0905andWeblate 8be1e78fee Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 93.1% (7924 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-25 17:32:15 +00:00
Zack the GhastandWeblate c463c99b0f Translated using Weblate (Portuguese (Portugal))
Currently translated at 60.8% (5178 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-06-25 17:32:13 +00:00
Polymeta 255829a9f8 Merge branch '1604-1-7-flying-crashes-the-game-if-pokeedit-is-used-on-the-specified-pokemon-beforehand-2' into 'main'
Resolve "[1.7] Flying crashes the game if /pokeedit is used on the specified Pokémon beforehand."

Closes #1575

See merge request cable-mc/cobblemon!1716
2025-06-25 14:43:18 +00:00
Josh 46758b7ab0 added ejectPassengers() to PokemonEntity#refreshRiding() 2025-06-25 09:57:14 -04:00
Polymeta aebcf42df8 Merge branch 'car-please-stop' into 'main'
Car please stop (Bug Fixes)

Closes #1584 and #1586

See merge request cable-mc/cobblemon!1698
2025-06-25 13:32:05 +00:00
AramandPolymeta 2268640dbc Car please stop (Bug Fixes) 2025-06-25 13:32:05 +00:00
Polymeta bf3739c598 Merge branch '1602-1-7-visible-held-items-appearing-on-unsupported-pokemon-through-pokeedit-command' into 'main'
Resolve "[1.7] Visible held items appearing on unsupported Pokémon through /pokeedit command."

Closes #1602

See merge request cable-mc/cobblemon!1714
2025-06-25 13:04:18 +00:00
Paul 9c4ae189a1 Optimize scriptable AI entities by only registering memories and sensors that are used by the task list 2025-06-25 22:29:16 +10:00
Zack the GhastandWeblate 502a314a6c Translated using Weblate (Portuguese (Portugal))
Currently translated at 60.6% (5159 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-06-25 03:50:36 +00:00
washashu0905andWeblate ca1ea6385d Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 89.3% (7598 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-25 03:50:36 +00:00
plastered_crab 9749acbb0c Fixes for behavior assignment of attacking hostile mobs 2025-06-24 08:29:17 -07:00
Josh 81d4e4ded1 refreshing riding settings in the ServerDelegate when the species is updated 2025-06-24 11:18:08 -04:00
Josh 3e5ab4328b locatorStates are now cleared when the species updates to remove non-existent locators 2025-06-24 10:50:55 -04:00
plastered_crab d1993574f6 some cleanup 2025-06-24 07:33:12 -07:00
plastered_crab 2b531ec32f Mons set to defend a Pasture are visually shown in the UI now 2025-06-24 06:28:34 -07:00
Paul a9985bbea8 Some pokemon have generational beef 2025-06-24 20:23:45 +10:00
plastered_crab 8d00da2c57 comma was missing for some reason 2025-06-24 00:45:50 -07:00
Zack the GhastandWeblate f4d866537a Translated using Weblate (Portuguese (Portugal))
Currently translated at 59.9% (5096 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-06-24 02:15:25 +00:00
Zack the GhastandWeblate e9f942687f Translated using Weblate (Portuguese (Portugal))
Currently translated at 59.8% (5092 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-06-23 23:36:40 +00:00
Josh d67d73351d updated LocatorAccess#update to remove locators that no longer exists 2025-06-23 16:03:26 -04:00
Josh 74d3ce793d removed the model argument for HeldItemRenderer since it is not really necessary 2025-06-23 16:00:19 -04:00
Polymeta 3223c8dfeb Merge branch 'Air-Ballon-Battle-Text-Fix' into 'main'
Fixed air balloon battle text not displaying the Pokemon or item name

See merge request cable-mc/cobblemon!1713
2025-06-23 13:03:56 +00:00
washashu0905andWeblate a84a897e84 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 88.2% (7505 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-23 12:08:59 +00:00
Landon Wills 92bf3ba2a2 Prevent players from mounting other players pokemon when owner is not mounted 2025-06-23 01:36:34 -04:00
Landon Wills 84f79c89c5 Dismount all passengers if driver dismounts 2025-06-22 23:16:35 -04:00
Landon Wills 248967256b Use bottom of pokemon hitbox for dismount position 2025-06-22 23:12:46 -04:00
Landon Wills ea19721998 Merge branch 'main' into multi-seat-mounts
# Conflicts:
#	common/src/main/resources/assets/cobblemon/bedrock/pokemon/models/0750_mudsdale/mudsdale.geo.json
2025-06-22 23:05:18 -04:00
Landon Wills e9408db7a1 Fix seat locator name always defaulting to seat_1 2025-06-22 23:03:54 -04:00
JazzMcNade 15ab84297d Update Changelog 2025-06-22 15:51:44 -05:00
JazzMcNade 94cfb23e66 Fixed air balloon battle text not displaying the pokemon or item name 2025-06-22 15:42:39 -05:00
Paul 2fbffa5b66 Birds will fly if it gets them out of water faster 2025-06-22 21:23:44 +10:00
washashu0905andWeblate 108b769928 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 84.0% (7145 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-22 06:31:58 +00:00
washashu0905andWeblate 3db39547f0 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 82.9% (7057 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-22 02:53:26 +00:00
washashu0905andWeblate c4688c5db9 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 81.9% (6969 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-22 02:11:11 +00:00
Paul b0385fc37f Added behaviour for NPC scale configuration 2025-06-22 11:59:36 +10:00
washashu0905andWeblate e491e7de81 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 81.3% (6922 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-06-21 15:11:30 +00:00
Tobias (Targ)andWeblate f7974767d1 Translated using Weblate (German)
Currently translated at 61.4% (5225 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2025-06-21 15:11:29 +00:00
Hiroku d41e89ddbd Merge branch 'we-arent-pushovers-anymore' into 'main'
Species JSON dictates if a species fights back or runs away from player that hurts it

See merge request cable-mc/cobblemon!1708
2025-06-21 03:44:48 +00:00
Hiroku 37293d396a Pastured pokemon react to damage too 2025-06-21 03:04:43 +00:00
Hiroku d598335112 Merge branch 'implement_pokemon' into 'main'
Implementation merge request, your majesty.

See merge request cable-mc/cobblemon!1711
2025-06-21 00:54:10 +00:00
plastered_crab a30ca92f0a Merge branch 'refs/heads/main' into we-must-defend-our-way-of-life
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/ai/config/task/TaskConfig.kt
2025-06-20 06:05:25 -07:00
plastered_crab dd5ec25345 Merge branch 'refs/heads/main' into we-arent-pushovers-anymore
# Conflicts:
#	common/src/main/resources/data/cobblemon/behaviours/pokemon/auto/pokemon_non_party.json
2025-06-20 06:03:58 -07:00
plastered_crab e3f3f4e1b7 fix rretaliation against attacking players 2025-06-19 21:45:34 -07:00
plastered_crab 004890d050 fix application of behavior 2025-06-19 21:39:27 -07:00
plastered_crab e690a0ed92 fix species json 2025-06-19 21:19:37 -07:00
plastered_crab 1e240d879f fix logic and species json 2025-06-19 21:04:26 -07:00
plastered_crab 5f52625b05 PasturePos is saved on tethering object. and make sure pasture mons don't defend areas too far away 2025-06-19 07:13:51 -07:00
plastered_crab 10746bea10 These darn u letters man 2025-06-19 03:29:39 -07:00
plastered_crab af1f607994 is_wild is now a pokemon entity Molang variable 2025-06-19 03:26:07 -07:00
plastered_crab db9cefc8ba is_wild is now a pokemon entity Molang variable 2025-06-19 03:14:17 -07:00
plastered_crab c467f9cad2 They call it AU because they add a u to everything 2025-06-19 01:53:34 -07:00
plastered_crab 5f7fa85b58 fix bool 2025-06-18 23:57:50 -07:00
plastered_crab eb3ffdfbd4 fix typos lol 2025-06-18 23:45:44 -07:00
阿鱼andWeblate c7e512bc32 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 87.9% (7479 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-18 10:11:29 +00:00
Watuneni iteiteandWeblate 6889cb7936 Translated using Weblate (Japanese)
Currently translated at 59.7% (5078 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-06-18 10:11:26 +00:00
plastered_crab b4af502997 testing with Charizard 2025-06-17 19:39:46 -07:00
plastered_crab 9bffdf8df4 testing with Charizard and Wimpod 2025-06-17 19:38:08 -07:00
plastered_crab 8dbdd78c86 testing with Charizard 2025-06-17 19:33:26 -07:00
plastered_crab e6812891b5 species json to allow for deciding if mons will defend their owner if in their party 2025-06-17 18:43:34 -07:00
plastered_crab 6a3c98ed1c species json to allow for deciding if mons will defend their owner if in their party 2025-06-17 18:42:34 -07:00
plastered_crab 991ec7cc1a species json to allow for deciding if mons flee or fight back when attacked 2025-06-17 18:06:36 -07:00
plastered_crab e59f4e7891 Guards find new targets once their first one dies 2025-06-15 21:03:57 -07:00
plastered_crab a481bde4f5 The guards are on active duty 2025-06-15 09:59:57 -07:00
阿鱼andWeblate 787faf38e7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 82.9% (7051 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-15 14:09:31 +00:00
Watuneni iteiteandWeblate 9a42c82a37 Translated using Weblate (Japanese)
Currently translated at 57.6% (4907 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-06-15 14:09:29 +00:00
plastered_crab 654d0f8975 You've never seen guard dogs like these before 2025-06-15 06:43:15 -07:00
plastered_crab 66b3c4a4c6 Scott has pooped so I must go 2025-06-15 04:57:53 -07:00
plastered_crab 2fc2f24dee yay it compiles. time for sleep finally. testing later 2025-06-14 16:57:50 -07:00
plastered_crab 0988411e13 Nothing to see here just some AI upgrade stuff 2025-06-14 14:52:56 -07:00
plastered_crab b39fadcde8 Nothing to see here just some AI upgrade stuff 2025-06-14 07:04:17 -07:00
阿鱼andWeblate 8221386767 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 79.0% (6722 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-11 18:24:33 +00:00
Nico MerenqandWeblate 311a3e1005 Translated using Weblate (Russian)
Currently translated at 51.9% (4417 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-06-09 15:14:52 +00:00
阿鱼andWeblate aeb6bddba6 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 64.9% (5521 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-09 15:14:52 +00:00
阿鱼andWeblate e11d1cb77c Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 63.9% (5436 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-09 14:54:27 +00:00
阿鱼andWeblate 774e62bb4b Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 55.1% (4691 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-09 14:46:08 +00:00
阿鱼andWeblate 716ab4fb95 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 50.5% (4296 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-09 14:39:15 +00:00
阿鱼andWeblate 766625bf31 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 81.2% (6912 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-09 14:23:36 +00:00
Nico MerenqandWeblate 14cde609c6 Translated using Weblate (Russian)
Currently translated at 51.9% (4416 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-06-09 14:23:35 +00:00
Nico MerenqandWeblate da6ac4b8d6 Translated using Weblate (Russian)
Currently translated at 51.9% (4416 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-06-08 20:39:07 +00:00
Nico MerenqandWeblate 43ef224444 Translated using Weblate (Russian)
Currently translated at 51.8% (4410 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ru/
2025-06-07 13:22:58 +00:00
阿鱼andWeblate d65d23ad02 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 78.4% (6671 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-06-05 09:16:15 +00:00
Watuneni iteiteandWeblate e32b540deb Translated using Weblate (Japanese)
Currently translated at 56.9% (4847 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-06-02 12:09:39 +00:00
Tobias (Targ)andWeblate f416567005 Translated using Weblate (German)
Currently translated at 61.3% (5217 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2025-06-02 12:09:37 +00:00
washashu0905andWeblate 1daf931a49 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 80.7% (6870 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-29 20:29:11 +00:00
Weblate 6bcbc58b0a 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-05-27 00:09:40 +00:00
Watuneni iteiteandWeblate a1218f6c1e Translated using Weblate (Japanese)
Currently translated at 55.6% (4731 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-05-27 00:09:36 +00:00
Tobias (Targ)andWeblate b1eb21150b Translated using Weblate (German)
Currently translated at 61.2% (5212 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2025-05-27 00:09:35 +00:00
Zack the GhastandWeblate 56d4a18474 Translated using Weblate (Portuguese (Portugal))
Currently translated at 59.5% (5062 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-24 03:06:49 +00:00
Zack the GhastandWeblate f13b6ddde7 Translated using Weblate (Portuguese (Portugal))
Currently translated at 59.3% (5051 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-23 22:41:49 +00:00
MiaandWeblate c3d119c197 Translated using Weblate (German)
Currently translated at 61.2% (5206 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2025-05-23 22:41:48 +00:00
Tobias (Targ)andWeblate eb7527c26c Translated using Weblate (German)
Currently translated at 61.2% (5206 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2025-05-23 22:41:48 +00:00
washashu0905andWeblate b6bc03d2b7 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 79.1% (6731 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-20 19:53:05 +00:00
Zack the GhastandWeblate 029a338aaf Translated using Weblate (Portuguese (Portugal))
Currently translated at 59.0% (5026 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-20 19:53:04 +00:00
washashu0905andWeblate b3f794ddaa Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 78.8% (6704 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-19 21:15:54 +00:00
Zack the GhastandWeblate 1c95686bf9 Translated using Weblate (Portuguese (Portugal))
Currently translated at 59.0% (5021 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-19 11:32:46 +00:00
Zack the GhastandWeblate 55b1e7c672 Translated using Weblate (Portuguese (Portugal))
Currently translated at 58.3% (4965 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-18 19:03:26 +00:00
washashu0905andWeblate e532fbf2ae Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 78.3% (6666 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-17 01:44:11 +00:00
Zack the GhastandWeblate c7348d3dba Translated using Weblate (Portuguese (Portugal))
Currently translated at 57.9% (4928 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-17 01:44:10 +00:00
Watuneni iteiteandWeblate b978bbe60e Translated using Weblate (Japanese)
Currently translated at 54.8% (4663 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-05-17 01:44:09 +00:00
washashu0905andWeblate 31c492c032 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 77.7% (6612 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-15 02:48:34 +00:00
阿鱼andWeblate 85a2142319 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 78.4% (6671 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-15 02:48:33 +00:00
Zack the GhastandWeblate 83e3d65918 Translated using Weblate (Portuguese (Portugal))
Currently translated at 56.6% (4818 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-15 02:48:32 +00:00
Watuneni iteiteandWeblate 9b053bef90 Translated using Weblate (Japanese)
Currently translated at 54.3% (4621 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-05-15 02:48:30 +00:00
Zack the GhastandWeblate 76211e81ff Translated using Weblate (Portuguese (Portugal))
Currently translated at 55.0% (4682 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-12 18:01:03 +00:00
washashu0905andWeblate 2cace9d153 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 76.5% (6510 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-12 04:29:57 +00:00
Zack the GhastandWeblate 33ad8ca12b Translated using Weblate (Portuguese (Portugal))
Currently translated at 54.4% (4633 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-12 04:29:56 +00:00
washashu0905andWeblate 8cce2c59b9 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 75.8% (6455 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-11 16:29:39 +00:00
阿鱼andWeblate bdcb8da6b7 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 77.0% (6553 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-11 16:29:38 +00:00
Zack the GhastandWeblate d0cfae8713 Translated using Weblate (Portuguese (Portugal))
Currently translated at 53.1% (4519 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-11 16:29:37 +00:00
阿鱼andWeblate 693b53704d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 76.9% (6543 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:55:19 +00:00
阿鱼andWeblate 3c46e3b5b9 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:52:03 +00:00
阿鱼andWeblate 5dec5ed008 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:52:00 +00:00
阿鱼andWeblate 22a479633e Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:57 +00:00
阿鱼andWeblate 1d93df56ae Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:53 +00:00
阿鱼andWeblate 136d47bd2f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:51 +00:00
阿鱼andWeblate 8ded0af5e9 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:47 +00:00
阿鱼andWeblate 36462b0a85 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:44 +00:00
阿鱼andWeblate 8a447a2487 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:41 +00:00
阿鱼andWeblate bdc2c4d9de Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:38 +00:00
阿鱼andWeblate 8d9a7d67b5 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:35 +00:00
阿鱼andWeblate e1d9b2780a Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:32 +00:00
阿鱼andWeblate fafee79da9 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:29 +00:00
阿鱼andWeblate 71c6c12656 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:26 +00:00
阿鱼andWeblate 4e07128c80 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:23 +00:00
north_82andWeblate df8640ce48 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:20 +00:00
阿鱼andWeblate 59e0a6369d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 72.8% (6194 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-10 12:51:19 +00:00
Zack the GhastandWeblate 8913252b79 Translated using Weblate (Portuguese (Portugal))
Currently translated at 51.1% (4353 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-10 12:51:17 +00:00
Zack the GhastandWeblate f7bedc9866 Translated using Weblate (Portuguese (Portugal))
Currently translated at 50.4% (4288 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-10 01:05:34 +00:00
washashu0905andWeblate e47529c10a Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 74.3% (6324 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-09 23:42:48 +00:00
Zack the GhastandWeblate 3e6c6c21a6 Translated using Weblate (Portuguese (Portugal))
Currently translated at 50.1% (4267 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-09 23:42:47 +00:00
washashu0905andWeblate d4f13b9435 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 73.0% (6216 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-09 12:41:51 +00:00
Zack the GhastandWeblate e7b60abe2d Translated using Weblate (Portuguese (Portugal))
Currently translated at 48.6% (4134 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-09 12:41:50 +00:00
TeggyandWeblate 85da2bd0cc Translated using Weblate (Spanish)
Currently translated at 77.0% (6554 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-05-09 12:41:48 +00:00
washashu0905andWeblate b7af57f6e1 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 72.7% (6187 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-06 09:41:57 +00:00
Aiser(CCHusky)andWeblate ca5b7e1aec Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 68.7% (5843 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-06 09:41:56 +00:00
阿鱼andWeblate 2ec81679e4 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 68.7% (5843 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-05-06 09:41:56 +00:00
Zack the GhastandWeblate 08c048f4ba Translated using Weblate (Portuguese (Portugal))
Currently translated at 41.2% (3508 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-06 09:41:55 +00:00
Watuneni iteiteandWeblate 6589279339 Translated using Weblate (Japanese)
Currently translated at 53.7% (4573 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/ja/
2025-05-06 09:41:53 +00:00
Alexis SalgueiroandWeblate 4465e47f2e Translated using Weblate (French)
Currently translated at 100.0% (8505 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-05-06 09:41:52 +00:00
YasitoandWeblate 570d42df7a Translated using Weblate (French)
Currently translated at 100.0% (8505 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-05-06 09:41:52 +00:00
YasitoandWeblate 044e83449d Translated using Weblate (French (Canada))
Currently translated at 100.0% (8505 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-05-06 09:41:50 +00:00
Felipe Bermudes OrmeñoandWeblate 6617558e71 Translated using Weblate (Spanish (Mexico))
Currently translated at 26.4% (2252 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es_MX/
2025-05-06 09:41:49 +00:00
TeggyandWeblate eff410b714 Translated using Weblate (Spanish)
Currently translated at 76.4% (6504 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-05-06 09:41:48 +00:00
Zack the GhastandWeblate 482a7d9493 Translated using Weblate (Portuguese (Portugal))
Currently translated at 35.9% (3058 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-03 09:32:24 +00:00
YasitoandWeblate 430891971c Translated using Weblate (French)
Currently translated at 97.2% (8275 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-05-03 09:32:24 +00:00
YasitoandWeblate d88f2d80a3 Translated using Weblate (French (Canada))
Currently translated at 100.0% (8505 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-05-03 09:32:23 +00:00
washashu0905andWeblate 2a3d74bd85 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 71.9% (6117 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-03 02:45:17 +00:00
Zack the GhastandWeblate de94986156 Translated using Weblate (Portuguese (Portugal))
Currently translated at 33.6% (2865 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-03 02:45:17 +00:00
YasitoandWeblate f8afcb6a8f Translated using Weblate (French)
Currently translated at 97.0% (8255 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-05-03 02:45:15 +00:00
YasitoandWeblate 3c0cf1dc5b Translated using Weblate (French (Canada))
Currently translated at 95.9% (8158 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-05-03 02:45:14 +00:00
Zack the GhastandWeblate 8225898a66 Translated using Weblate (Portuguese (Portugal))
Currently translated at 26.8% (2283 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-02 07:52:09 +00:00
washashu0905andWeblate 49faf60ea1 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 70.2% (5976 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-02 07:52:09 +00:00
Weblate 71bd4fb610 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-05-01 21:54:39 +00:00
Felipe Bermudes OrmeñoandWeblate 509feae420 Translated using Weblate (Spanish (Mexico))
Currently translated at 24.7% (2103 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es_MX/
2025-05-01 21:54:34 +00:00
washashu0905andWeblate 5045a95cd0 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 69.9% (5946 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-05-01 21:54:33 +00:00
TeggyandWeblate 07dfc89f63 Translated using Weblate (Spanish)
Currently translated at 72.8% (6196 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-05-01 21:54:30 +00:00
Zack the GhastandWeblate 34b6a3cc47 Translated using Weblate (Portuguese (Portugal))
Currently translated at 26.6% (2266 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-05-01 21:54:29 +00:00
YasitoandWeblate 98fd61ec29 Translated using Weblate (French (Canada))
Currently translated at 92.5% (7875 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-29 16:26:11 +00:00
washashu0905andWeblate e1e545dd05 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 58.5% (4979 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-04-29 16:26:07 +00:00
Zack the GhastandWeblate c403103018 Translated using Weblate (Portuguese (Portugal))
Currently translated at 21.2% (1811 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-04-29 16:26:05 +00:00
Alexis SalgueiroandWeblate d6a1d3f2bd Translated using Weblate (French)
Currently translated at 95.3% (8110 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-29 16:26:05 +00:00
YasitoandWeblate 87edf2bfd6 Translated using Weblate (French)
Currently translated at 95.3% (8110 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-29 16:26:04 +00:00
阿鱼andWeblate 7711535a26 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 67.3% (5731 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-04-29 16:26:02 +00:00
YasitoandWeblate f65f6fd2c9 Translated using Weblate (French (Canada))
Currently translated at 89.0% (7575 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 07:11:57 +00:00
YasitoandWeblate a4e144854d Translated using Weblate (French)
Currently translated at 93.8% (7981 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 07:11:56 +00:00
Weblate d6f7cd4b83 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-04-28 06:06:01 +00:00
YasitoandWeblate 36cf258410 Translated using Weblate (French)
Currently translated at 92.6% (7876 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 06:05:56 +00:00
YasitoandWeblate 89df2a01e2 Translated using Weblate (French)
Currently translated at 86.8% (7387 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 05:33:24 +00:00
YasitoandWeblate 0a930cb54f Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 05:07:13 +00:00
YasitoandWeblate 2448fec2c4 Translated using Weblate (French (Canada))
Currently translated at 88.9% (7568 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 05:07:13 +00:00
YasitoandWeblate ea2071b644 Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 04:50:27 +00:00
YasitoandWeblate bae0d77699 Translated using Weblate (French (Canada))
Currently translated at 88.9% (7564 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 04:50:27 +00:00
YasitoandWeblate f5f5cb19bc Translated using Weblate (French (Canada))
Currently translated at 88.5% (7527 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 04:41:03 +00:00
YasitoandWeblate 9aa7c65279 Translated using Weblate (French (Canada))
Currently translated at 87.6% (7451 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 04:21:08 +00:00
YasitoandWeblate 8f4071e181 Translated using Weblate (French (Canada))
Currently translated at 83.6% (7114 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 03:12:58 +00:00
YasitoandWeblate 9c4470bc51 Translated using Weblate (French (Canada))
Currently translated at 82.8% (7043 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 02:57:15 +00:00
YasitoandWeblate c785480c32 Translated using Weblate (French (Canada))
Currently translated at 82.7% (7034 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 02:55:09 +00:00
YasitoandWeblate 4a50700bb9 Translated using Weblate (French (Canada))
Currently translated at 82.4% (7014 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 02:31:04 +00:00
YasitoandWeblate 0ad2ff552b Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 02:31:03 +00:00
YasitoandWeblate 44c5d4ea2e Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 02:07:34 +00:00
YasitoandWeblate 46661908e0 Translated using Weblate (French (Canada))
Currently translated at 82.4% (7013 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 02:07:33 +00:00
YasitoandWeblate 01372f2850 Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 01:26:15 +00:00
YasitoandWeblate 204ce8f003 Translated using Weblate (French (Canada))
Currently translated at 81.7% (6954 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 01:26:15 +00:00
Zack the GhastandWeblate 784ddcb19a Translated using Weblate (Portuguese (Portugal))
Currently translated at 20.9% (1785 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-04-28 01:26:13 +00:00
Zack the GhastandWeblate 11d7cbfa46 Translated using Weblate (Portuguese (Portugal))
Currently translated at 20.9% (1785 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-04-28 00:34:45 +00:00
YasitoandWeblate f3325caaea Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-28 00:34:44 +00:00
YasitoandWeblate 123c348f73 Translated using Weblate (French (Canada))
Currently translated at 81.2% (6910 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-28 00:34:43 +00:00
Zack the GhastandWeblate 29aae87f01 Translated using Weblate (Portuguese (Portugal))
Currently translated at 20.9% (1785 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2025-04-27 23:55:57 +00:00
YasitoandWeblate 9f6ad98acb Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 23:45:29 +00:00
YasitoandWeblate cecd291566 Translated using Weblate (French (Canada))
Currently translated at 81.1% (6905 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 23:45:28 +00:00
YasitoandWeblate 2f9d6a9f83 Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 22:59:22 +00:00
YasitoandWeblate 1e9ccbddcb Translated using Weblate (French (Canada))
Currently translated at 81.0% (6893 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 22:59:21 +00:00
YasitoandWeblate 9b5a381436 Translated using Weblate (French (Canada))
Currently translated at 81.0% (6891 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 22:53:05 +00:00
YasitoandWeblate ed5bd7e899 Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 22:53:04 +00:00
YasitoandWeblate 587a90bb70 Translated using Weblate (French)
Currently translated at 86.8% (7386 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 22:24:54 +00:00
YasitoandWeblate f883578046 Translated using Weblate (French (Canada))
Currently translated at 80.8% (6873 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 22:24:48 +00:00
YasitoandWeblate b5d348eba6 Translated using Weblate (French (Canada))
Currently translated at 80.3% (6830 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 21:40:48 +00:00
YasitoandWeblate fce389edfd Translated using Weblate (French (Canada))
Currently translated at 77.5% (6594 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 19:59:05 +00:00
YasitoandWeblate b6954b4e07 Translated using Weblate (French (Canada))
Currently translated at 76.6% (6523 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 19:31:52 +00:00
YasitoandWeblate f28a16c7cc Translated using Weblate (French (Canada))
Currently translated at 76.2% (6488 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 19:17:12 +00:00
YasitoandWeblate 230071a773 Translated using Weblate (French (Canada))
Currently translated at 75.9% (6456 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 18:59:21 +00:00
YasitoandWeblate 63534a242c Translated using Weblate (French (Canada))
Currently translated at 75.8% (6449 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 18:54:07 +00:00
YasitoandWeblate 1afb574aec Translated using Weblate (French (Canada))
Currently translated at 75.5% (6427 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 17:58:35 +00:00
YasitoandWeblate ac9adb03cd Translated using Weblate (French)
Currently translated at 81.5% (6938 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 17:58:34 +00:00
YasitoandWeblate f3a22b19b3 Translated using Weblate (French (Canada))
Currently translated at 75.5% (6427 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 17:23:59 +00:00
YasitoandWeblate 572e77c4f5 Translated using Weblate (French (Canada))
Currently translated at 75.5% (6426 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 08:45:10 +00:00
YasitoandWeblate 889a012932 Translated using Weblate (French)
Currently translated at 81.5% (6938 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 08:45:09 +00:00
YasitoandWeblate eca4c6cd4c Translated using Weblate (French)
Currently translated at 81.5% (6938 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 08:29:53 +00:00
YasitoandWeblate b570a6ec8b Translated using Weblate (French (Canada))
Currently translated at 75.5% (6426 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 08:29:52 +00:00
YasitoandWeblate 1f1c302bc9 Translated using Weblate (French (Canada))
Currently translated at 75.5% (6426 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 08:13:24 +00:00
YasitoandWeblate adc1fa0063 Translated using Weblate (French)
Currently translated at 81.5% (6938 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 08:13:23 +00:00
YasitoandWeblate ddc3a781a0 Translated using Weblate (French)
Currently translated at 81.4% (6930 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 06:49:52 +00:00
YasitoandWeblate 9eb3281c6f Translated using Weblate (French)
Currently translated at 79.8% (6793 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 06:26:21 +00:00
YasitoandWeblate 0cd5804e67 Translated using Weblate (French)
Currently translated at 77.0% (6549 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 05:59:16 +00:00
YasitoandWeblate 7000d0d82a Translated using Weblate (French)
Currently translated at 74.8% (6369 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 05:26:22 +00:00
YasitoandWeblate b7695e55ea Translated using Weblate (French)
Currently translated at 68.5% (5829 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 04:36:54 +00:00
YasitoandWeblate bea3ebe62b Translated using Weblate (French)
Currently translated at 68.4% (5825 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 04:35:43 +00:00
YasitoandWeblate 73cf736077 Translated using Weblate (French (Canada))
Currently translated at 75.4% (6413 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 04:05:10 +00:00
YasitoandWeblate d31f8f0eff Translated using Weblate (French)
Currently translated at 68.1% (5797 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 04:05:09 +00:00
YasitoandWeblate 88dca4d7b1 Translated using Weblate (French (Canada))
Currently translated at 75.3% (6410 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 03:22:47 +00:00
YasitoandWeblate 27db85ee32 Translated using Weblate (French (Canada))
Currently translated at 75.3% (6406 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 03:09:50 +00:00
YasitoandWeblate 5e3561eba5 Translated using Weblate (French (Canada))
Currently translated at 75.2% (6400 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 03:02:48 +00:00
YasitoandWeblate 9dfa8a323e Translated using Weblate (French)
Currently translated at 68.1% (5797 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 02:21:41 +00:00
YasitoandWeblate 15c0d86996 Translated using Weblate (French (Canada))
Currently translated at 74.9% (6371 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 02:21:37 +00:00
Weblate 0fbb5e7d95 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-04-27 00:08:16 +00:00
YasitoandWeblate 5e8d27779c Translated using Weblate (French (Canada))
Currently translated at 73.6% (6265 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-27 00:08:12 +00:00
阿鱼andWeblate a4fabcd45d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 66.3% (5647 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-04-27 00:08:10 +00:00
YasitoandWeblate 5259b8c93d Translated using Weblate (French)
Currently translated at 68.1% (5797 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-27 00:08:09 +00:00
YasitoandWeblate 397c2decbf Translated using Weblate (French)
Currently translated at 67.8% (5772 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-25 04:29:11 +00:00
Felipe Bermudes OrmeñoandWeblate 12b6e7e49c Translated using Weblate (Spanish (Mexico))
Currently translated at 24.6% (2098 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es_MX/
2025-04-25 04:29:10 +00:00
YasitoandWeblate 242c1b01af Translated using Weblate (French (Canada))
Currently translated at 69.4% (5906 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-25 04:29:09 +00:00
Felipe Bermudes OrmeñoandWeblate ee76e19b85 Translated using Weblate (Spanish (Mexico))
Currently translated at 23.7% (2017 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es_MX/
2025-04-22 09:14:36 +00:00
YasitoandWeblate 2aac6cc9e7 Translated using Weblate (French)
Currently translated at 67.6% (5754 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-22 09:14:35 +00:00
YasitoandWeblate 3faa305f09 Translated using Weblate (French (Canada))
Currently translated at 59.0% (5026 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-22 09:14:34 +00:00
YasitoandWeblate d1bbf5f079 Translated using Weblate (French)
Currently translated at 67.1% (5715 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-21 23:59:12 +00:00
YasitoandWeblate 52fa646420 Translated using Weblate (French (Canada))
Currently translated at 56.5% (4813 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-21 23:59:11 +00:00
Alexis SalgueiroandWeblate f7c47d46cf Translated using Weblate (French)
Currently translated at 66.5% (5658 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-21 14:21:10 +00:00
YasitoandWeblate e82c361bcb Translated using Weblate (French)
Currently translated at 66.5% (5658 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2025-04-21 14:21:10 +00:00
TeggyandWeblate fa6d8e0f08 Translated using Weblate (Spanish)
Currently translated at 72.5% (6168 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-04-21 14:21:06 +00:00
阿鱼andWeblate 7eea6c8b49 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 66.3% (5643 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2025-04-21 14:21:03 +00:00
YasitoandWeblate c537ca438b Translated using Weblate (French (Canada))
Currently translated at 55.4% (4720 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr_CA/
2025-04-21 14:21:01 +00:00
washashu0905andWeblate d5cea9b9ad Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 53.1% (4518 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2025-04-21 14:20:57 +00:00
TeggyandWeblate 6c2494b7ab Translated using Weblate (Spanish)
Currently translated at 68.2% (5806 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-04-19 19:31:37 +00:00
Fiestorra ISVandWeblate a5ab523ac1 Translated using Weblate (Spanish)
Currently translated at 66.6% (5672 of 8505 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-04-19 06:05:19 +00:00
Weblate 847ae12ad5 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-04-18 21:50:21 +00:00
TeggyandWeblate cece9e051b Translated using Weblate (Spanish)
Currently translated at 98.9% (6948 of 7021 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-04-18 21:50:21 +00:00
Fiestorra ISVandWeblate 02141ccd3e Translated using Weblate (Spanish)
Currently translated at 98.9% (6948 of 7021 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2025-04-18 21:50:21 +00:00
MiaandWeblate 1dc3acc47d Translated using Weblate (German)
Currently translated at 87.2% (6124 of 7021 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2025-04-18 21:50:21 +00:00
504 changed files with 33398 additions and 16036 deletions
+5 -1
View File
@@ -5,12 +5,16 @@
- Dog Pokémon (Growlithe, Arcanine, etc.) intimidate Skeletons.
- Cat Pokémon (Meowth, Persian, etc.) intimidate Creepers and Phantoms.
- Sleep-related Pokémon (Munsharna, Komala, etc.) intimidate Phantoms.
- Some Pokémon naturally hunt each other.
- Added a Behaviour Editor to the NPC editing screen.
- Added /behaviouredit command for opening the Behaviour Editor on Pokémon and NPCs.
- Editing variables for Pokémon is not yet supported.
### Developer
- baseScale in NPCs has been removed from classes and presets, and in the entity it is replaced with hitboxScale and renderScale.
### MoLang & Datapacks
- Added a `behaviours` datapack folder which motivates the Behaviour Editor screen on NPCs and Pokémon.
- Added many default behaviours.
- Added very many behaviours to choose from.
- Removed many NPC presets that now exist as behaviours. This is a breaking change if you are using NPCs with these presets.
- NPCs with these presets should be modified to instead list under `"behaviours"` all the equivalent behaviours.
+7 -1
View File
@@ -4,10 +4,16 @@
- The button on the right allows for changing the box wallpaper.
- The option buttons on the left side allow for sorting the box by name, level, Pokédex number, gender, and type. Shift clicking allows for sorting in reverse order.
- Added filter functionality in PC UI, which supports `PokemonProperties` (e.g. `shiny=yes` shows all shiny Pokémon).
- Names can be filtered by exact or partial matches, e.g. entering "cha" will show Charmander, Charmeleon, etc.
- Added `/changewallpaper <player> <boxNumber> <wallpaper>` command to change a box wallpaper through commands.
- Added `/renamebox <player> <boxNumber> <name>` command to rename a PC box through commands.
- Added IVs and EVs stat displays in PC.
- improved filter by Name, now is available search by exact names or partial matches, for example "cha" will show Charmander, Charmeleon and Charizard among others that match.
- Added ability to change boxes by scrolling.
- PC will now open to last box viewed within a session.
### Changes
- Slots in pastures will now have darker backgrounds and italicised Pokémon names if the Pokémon is not owned by the player.
- The pasture slot will show the name of the Pokémon owner when hovered if the Pokémon is not owned.
### Developer
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
+17 -7
View File
@@ -20,9 +20,8 @@
- The player executing the command must be facing the target pokemon entity. Transformations are not persistent and will revert when resources are reloaded.
- Added `legacy` and `special` sourced moves to Pokémon.
- Added lang keys for all moves and abilities up to Generation 9.
- Fixed Moon Ball moon phase logic to actually work correctly
- Added `translucent_cull` boolean option into resolver's layer to allow for translucent textures with culling
- Added [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) support for items held by Pokémon.
- Added [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) support for items held by Pokémon, evolution stone blocks, evolution stone items, Pokédex, Luminous Moss, Flame Orb, and Magmarizer.
- Added the Clear Amulet, Grip Claw, Lagging Tail, Luminous Moss, Metal Alloy, Scroll of Darkness, Scroll of Waters
- Added Recipes for Masterpiece Cup, Eject Pack
- Added modification to Minecraft Creative Inventory search to account for item names that contain `poké` when input contains `poke`.
@@ -33,6 +32,7 @@
- Added `/pctake <player> <box> <slot>` command that takes a specific Pokémon from a player's PC. Removes the pokemon if target is self or ran from the server.
- Added Hyper Training items (IV Modification) as well as some additional candy items to do so (Health Candy, Sickly Candy)
- Added Galarica Nut Bushes
- Added functionality to Everstone when held by a Pokémon; suppresses evolution notification and hides evolve button in summary interface.
### Pokémon Added
@@ -226,6 +226,9 @@
- Saccharine Leaves Age 1 or higher will now show Yellow particles when broken
- Destroying a Saccharine Honey Log will now drop a Saccharine Log in stead of nothing
- Reworked some compost chances
- Updated interaction interface to include 4 more option spaces
- Made lecterns that hold a Pokédex emit light.
- Updated light levels for active PC, Pasture, Healing Machine, and Data Monitor.
### Fixes
- Fixed game crashing when removing national pokedex using datapacks
@@ -280,12 +283,17 @@
- Fixed Cobblemon crashing if it tries to load a bedrock model not meant for cobblemon (example: Qlipoth Awakening)
- Fixed Berries (and thus mulches) not being plantable on Farmers delight rich soil farmland
- Fixed wild Pokémon vanishing when third party mods try to tame them the "vanilla" way
- Fixed Pokemon not being able to path over skulk veins, pressure plates, fence gates, signs, lanterns, chains, and many other short blocks.
- Fixed some cases in which Pokemon could not path over fence posts situations.
- Fixed Pokémon not being able to path over skulk veins, pressure plates, fence gates, signs, lanterns, chains, and many other short blocks.
- Fixed some cases in which Pokémon could not path over fence posts situations.
- Fixed flyers not being able to do vertical takeoff if surrounded by blocks.
- Fixed swimming Pokemon attempting to swim up through solid blocks.
- Fixed Pokemon surface swimming diving downward a block for the duration of the swim.
- Fixed swimming Pokémon attempting to swim up through solid blocks.
- Fixed Pokémon surface swimming diving downward a block for the duration of the swim.
- Improved flyers avoiding getting stuck on fence posts.
- Fixed air balloon battle text not correctly displaying the Pokémon or item name
- Fixed an issue where items retrieved from a Display case would disappear if a player's inventory is full
- Fixed Pokédex Scanner not respecting the "Invert Mouse" option.
- Fixed a crash due to a ConcurrentModificationException that could occur during world generation.
- Fixed Moon Ball moon phase logic to actually work correctly
- Fixed recoil eyes on Shellder & Cloyster.
- Fixed Shroomish spinning at lightning speed when fainting (no longer allowed to let it rip.)
- Fixed Quaxly's animations showing hidden wing sets
@@ -324,7 +332,9 @@
- Added `Pokemon#hyperTrainIV()` and `IVs#setHyperTrainedIV(Stat, Int)`.
- Added `HyperTrainedIvEvent.Pre` and `HyperTrainedIvEvent.Post`.
- Added a `hoverText` option to PartySelectCallback, to display a tooltip on hovering over a Pokémon in the selection screen.
- `PokemonEntity` instances spawned into the world now appropriately finalize the spawn for mod compatibility.
- Added PokedexManager.obtain as a replacement for .catch which is not a friendly function name in Java.
### MoLang & Datapacks
- The following usages for item predicates can now use item conditions like advancements do, you can learn about them in the [Minecraft wiki](https://minecraft.wiki/w/Advancement_definition#minecraft:filled_bucket)
- The `requiredContext` for an item interaction evolution
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.compat;
import com.cobblemon.mod.common.CobblemonEntities;
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.item.PokedexItem;
import com.cobblemon.mod.common.pokemon.FormData;
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
import dev.lambdaurora.lambdynlights.LambDynLights;
@@ -36,20 +37,20 @@ public class LambDynamicLightsCompat {
public static void hookCompat() {
// Pokémon entities
DynamicLightHandlers.registerDynamicLightHandler(
CobblemonEntities.POKEMON,
DynamicLightHandler.makeHandler(
LambDynamicLightsCompat::resolvedPokemonLightLevel,
pokemon -> false
)
CobblemonEntities.POKEMON,
DynamicLightHandler.makeHandler(
LambDynamicLightsCompat::resolvedPokemonLightLevel,
pokemon -> false
)
);
// Shouldered Pokémon
DynamicLightHandlers.registerDynamicLightHandler(
EntityType.PLAYER,
DynamicLightHandler.makeHandler(
LambDynamicLightsCompat::resolvedShoulderLightLevel,
player -> false
)
EntityType.PLAYER,
DynamicLightHandler.makeHandler(
LambDynamicLightsCompat::resolvedPlayerLightLevel,
player -> false
)
);
}
@@ -63,11 +64,13 @@ public class LambDynamicLightsCompat {
return Math.max(itemLightLevel, formLightLevel);
}
private static int resolvedShoulderLightLevel(Player player) {
private static int resolvedPlayerLightLevel(Player player) {
var underwater = !player.level().getFluidState(BlockPos.containing(player.getX(), player.getEyeY(), player.getZ())).isEmpty();
final int leftLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft()), underwater);
final int rightLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight()), underwater);
return Math.max(leftLightLevel, rightLightLevel);
final int leftShoulderLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft()), underwater);
final int rightShoulderLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight()), underwater);
final int itemLightLevel = customHeldItemLightLevel(player.getMainHandItem(), player.getOffhandItem());
return Math.max(itemLightLevel, Math.max(leftShoulderLightLevel, rightShoulderLightLevel));
}
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
@@ -83,14 +86,17 @@ public class LambDynamicLightsCompat {
}
ItemStack item = shoulderData.getShownItem();
int itemLightLevel = item.isEmpty()?0:LambDynLights.getLuminanceFromItemStack(item, underwater);
int itemLightLevel = item.isEmpty() ? 0 :LambDynLights.getLuminanceFromItemStack(item, underwater);
int formLightLevel = extractFormLightLevel(shoulderData.getForm(), underwater).orElse(0);
return Math.max(itemLightLevel, formLightLevel);
}
private static int customHeldItemLightLevel(ItemStack mainhand, ItemStack offhand) {
return (mainhand.getItem() instanceof PokedexItem || offhand.getItem() instanceof PokedexItem) ? 13 : 0;
}
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
}
}
@@ -12,14 +12,12 @@ import com.cobblemon.mod.common.block.SaccharineLeafBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.objectweb.asm.Opcodes;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Desc;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@@ -42,8 +40,9 @@ public abstract class BeeEntityMixin {
if (block instanceof SaccharineLeafBlock) {
int age = blockState.getValue(SaccharineLeafBlock.Companion.getAGE());
boolean waterlogged = blockState.getValue(BlockStateProperties.WATERLOGGED);
if (age < 2) {
if (age < 2 && !waterlogged) {
this.cobblemon$result = blockState.setValue(SaccharineLeafBlock.Companion.getAGE(), age + 1);
}
}
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
import net.minecraft.world.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
@Mixin(ClientPacketListener.class)
public class ClientPacketListenerMixin {
@Shadow private ClientLevel level;
@Inject(method = "handleSetEntityPassengersPacket", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/entity/Entity;hasIndirectPassenger(Lnet/minecraft/world/entity/Entity;)Z", shift = At.Shift.BEFORE), cancellable = true)
private void cobblemon$handlePokemonPassengers(ClientboundSetPassengersPacket packet, CallbackInfo ci) {
Entity entity = this.level.getEntity(packet.getVehicle());
if (entity instanceof PokemonEntity pokemon) {
var passengers = new ArrayList<Entity>();
for (int passenger : packet.getPassengers()) {
passengers.add(this.level.getEntity(passenger));
}
Arrays
.stream(pokemon.getOccupiedSeats())
.filter(x -> !passengers.contains(x))
.filter(Objects::nonNull)
.forEach(Entity::stopRiding);
var occupiedSeats = Arrays.asList(pokemon.getOccupiedSeats());
passengers.stream()
.filter(x -> !occupiedSeats.contains(x))
.filter(Objects::nonNull)
.forEach(x -> x.startRiding(pokemon, true));
ci.cancel();
}
}
}
@@ -9,20 +9,19 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState;
import com.cobblemon.mod.common.entity.PosableEntity;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.resources.PlayerSkin;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Debug;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -30,11 +29,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.resources.PlayerSkin;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.entity.player.Player;
@Mixin(EntityRenderDispatcher.class)
public class EntityRenderDispatcherMixin {
@@ -77,6 +71,23 @@ public class EntityRenderDispatcherMixin {
0F,
1F
);
/*if (locator.contains("middle")){
PoseStack.Pose pose = poseStack.last();
Vector3f vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(0, 0, -1));
buffer.addVertex(pose, pos.toVector3f()).setColor(0xffff00ff).setNormal(pose, vec.x, vec.y, vec.z); //Forward, pink
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xffff00ff).setNormal(pose, vec.x, vec.y, vec.z);
vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(0, 1, 0));
buffer.addVertex(pose, pos.toVector3f()).setColor(0xffffff00).setNormal(pose, vec.x, vec.y, vec.z); //Up, yellow
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xffffff00).setNormal(pose, vec.x, vec.y, vec.z);
vec = matrix.getMatrix().getRotation(new AxisAngle4f()).transform(new Vector3f(-1, 0, 0));
buffer.addVertex(pose, pos.toVector3f()).setColor(0xff00ffff).setNormal(pose, vec.x, vec.y, vec.z); //Left, cyan
buffer.addVertex(pose, (float)(pos.x() + vec.x), (float)(pos.y() + vec.y), (float)(pos.z() + vec.z)).setColor(0xff00ffff).setNormal(pose, vec.x, vec.y, vec.z);
}*/
poseStack.popPose();
});
@@ -119,14 +119,12 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
Entity vehicle = this.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity) {
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
Seat seat = pokemonEntity.getSeats().get(seatIndex);
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
String locatorName = delegate.getSeatLocator(this);
MatrixWrapper locator = delegate.getLocatorStates().get(locatorName);
if (locator == null) {
super.pick(hitDistance, partialTicks, hitFluids);
return super.pick(hitDistance, partialTicks, hitFluids);
}
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
@@ -138,7 +136,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) {
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemonEntity.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
offset.add(cobblemon$getFirstPersonOffset(model, seat));
offset.add(cobblemon$getFirstPersonOffset(model, locatorName));
}
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
@@ -160,11 +158,11 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
}
@Unique
private static @NotNull Vector3f cobblemon$getFirstPersonOffset(PosableModel model, Seat seat) {
private static @NotNull Vector3f cobblemon$getFirstPersonOffset(PosableModel model, String locatorName) {
Map<String, Vec3> cameraOffsets = model.getFirstPersonCameraOffset();
if (cameraOffsets.containsKey(seat.getLocator())) {
return cameraOffsets.get(seat.getLocator()).toVector3f();
if (cameraOffsets.containsKey(locatorName)) {
return cameraOffsets.get(locatorName).toVector3f();
} else {
return new Vector3f(0f, 0f, 0f);
}
@@ -30,7 +30,6 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(MouseHandler.class)
public abstract class MouseHandlerMixin {
@@ -121,11 +120,12 @@ public abstract class MouseHandlerMixin {
if (usageContext.getScanningGuiOpen()) {
this.smoothTurnY.reset();
this.smoothTurnX.reset();
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6 + 0.2;
var spyglassSensitivity = Math.pow(defaultSensitivity, 3);
var lookSensitivity = spyglassSensitivity * 8.0;
var sensitivity = Mth.lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity));
var yRotationFlip = this.minecraft.options.invertYMouse().get() ? -1 : 1;
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity * yRotationFlip));
return false;
}
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client.snapshots;
import com.cobblemon.mod.common.CobblemonBuildDetails;
import com.cobblemon.mod.common.client.gui.snapshots.SnapshotWarningScreen;
import com.cobblemon.mod.common.client.snapshots.SnapshotAcknowledgementData;
import com.cobblemon.mod.common.client.snapshots.SnapshotAcknowledgementReader;
import kotlin.Unit;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Mixin(Minecraft.class)
public final class SnapshotWarningMixin {
@Unique
private final Pattern VERSION = Pattern.compile("^(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)$");
@Inject(method = "addInitialScreens", at = @At("TAIL"))
public void cobblemon$addSnapshotWarningScreen(List<Function<Runnable, Screen>> output, CallbackInfo callback) {
if (CobblemonBuildDetails.SNAPSHOT && !this.cobblemon$isAcknowledged() && !SharedConstants.IS_RUNNING_IN_IDE) {
output.add((runnable) -> new SnapshotWarningScreen((acknowledgement, dsa) -> {
if (acknowledgement == SnapshotWarningScreen.Acknowledgement.NO) {
Minecraft.getInstance().stop();
return Unit.INSTANCE;
}
SnapshotAcknowledgementReader.INSTANCE.write(new SnapshotAcknowledgementData(CobblemonBuildDetails.VERSION, dsa));
runnable.run();
return Unit.INSTANCE;
}));
}
}
@Unique
@SuppressWarnings("ResultOfMethodCallIgnored")
private boolean cobblemon$isAcknowledged() {
SnapshotAcknowledgementData data = SnapshotAcknowledgementReader.INSTANCE.read();
if (data == null) {
return false;
}
Matcher current = VERSION.matcher(CobblemonBuildDetails.VERSION);
current.find();
Matcher when = VERSION.matcher(data.getVersion());
when.find();
boolean alert = current.group("minor").compareTo(when.group("minor")) > 0 || current.group("major").compareTo(when.group("major")) > 0;
return !alert && data.getDontShowAgain();
}
}
@@ -25,6 +25,8 @@ import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionOrEntityVariableAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.MemoryModuleTypeAdapter
import com.cobblemon.mod.common.util.adapters.SensorTypeAdapter
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
import com.cobblemon.mod.common.util.cobblemonResource
@@ -39,6 +41,8 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.server.packs.resources.ResourceManager
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
import net.minecraft.world.entity.schedule.Activity
object CobblemonBehaviours : JsonDataRegistry<CobblemonBehaviour> {
@@ -47,6 +51,8 @@ object CobblemonBehaviours : JsonDataRegistry<CobblemonBehaviour> {
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(MemoryModuleType::class.java, MemoryModuleTypeAdapter)
.registerTypeAdapter(SensorType::class.java, SensorTypeAdapter)
.registerTypeAdapter(BehaviourConfig::class.java, BehaviourConfigAdapter)
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
.registerTypeAdapter(
@@ -34,13 +34,10 @@ import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.valueproviders.UniformInt
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.EntityType
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.*
import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.block.state.BlockBehaviour.Properties
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.properties.BlockSetType
import net.minecraft.world.level.block.state.properties.BlockStateProperties.LIT
@@ -179,7 +176,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val SACCHARINE_LOG = this.create("saccharine_log", SaccharineLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava()))
@JvmField
val SACCHARINE_HONEY_LOG = this.create("saccharine_honey_log", SaccharineHoneyLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava()))
val SACCHARINE_LOG_SLATHERED = this.create("saccharine_log_slathered", SaccharineLogSlatheredBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava()))
@JvmField
val STRIPPED_SACCHARINE_LOG = this.create("stripped_saccharine_log", RotatedPillarBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
@@ -208,7 +205,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val SACCHARINE_FENCE = this.create("saccharine_fence", FenceBlock(BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
@JvmField
val SACCHARINE_FENCE_GATE = this.create("saccharine_fence_gate", FenceGateBlock(SACCHARINE_WOOD_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
@JvmField
val SACCHARINE_BUTTON = this.create("saccharine_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
@JvmField
val SACCHARINE_PRESSURE_PLATE = this.create("saccharine_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).noCollission().strength(0.5f).sound(SoundType.WOOD)))
@@ -477,20 +474,20 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val GIMMIGHOUL_CHEST = create("gimmighoul_chest", GildedChestBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.CHEST).noOcclusion().sound(CobblemonSounds.GILDED_CHEST_SOUNDS), GildedChestBlock.Type.FAKE))
@JvmField
val MONITOR = create("monitor", MonitorBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).lightLevel { if (it.getValue(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 15 else 0 }))
val MONITOR = create("monitor", MonitorBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).lightLevel { if (it.getValue(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 13 else 0 }))
@JvmField
val FOSSIL_ANALYZER = create("fossil_analyzer", FossilAnalyzerBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).noOcclusion()))
@JvmField
val RESTORATION_TANK = create("restoration_tank", RestorationTankBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.GLASS).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).noOcclusion()))
@JvmField
val HEALING_MACHINE = create("healing_machine", HealingMachineBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2f).noOcclusion().lightLevel { if (it.getValue(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 7 else 2 }))
val HEALING_MACHINE = create("healing_machine", HealingMachineBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2f).noOcclusion().lightLevel { if (it.getValue(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 12 else 5 }))
@JvmField
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }))
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 13 else 0 }))
@JvmField
val LECTERN = create("lectern", LecternBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).sound(SoundType.WOOD).strength(2.5F).ignitedByLava()))
val LECTERN = create("lectern", LecternBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).sound(SoundType.WOOD).strength(2.5F).ignitedByLava().lightLevel { if (it.getValue(LecternBlock.EMIT_LIGHT) as Boolean) 13 else 0 }))
@JvmField
val DISPLAY_CASE = create("display_case", DisplayCaseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3F).requiresCorrectToolForDrops()))
@@ -499,7 +496,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val INCENSE_SWEET = create("incense_sweet", SweetIncenseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3f)))
@JvmField
val PASTURE = create("pasture", PastureBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BROWN).sound(SoundType.WOOD).strength(2F).noOcclusion().pushReaction(PushReaction.BLOCK).lightLevel { if ((it.getValue(PastureBlock.ON) as Boolean) && (it.getValue(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 10 else 0 }))
val PASTURE = create("pasture", PastureBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BROWN).sound(SoundType.WOOD).strength(2F).noOcclusion().pushReaction(PushReaction.BLOCK).lightLevel { if ((it.getValue(PastureBlock.ON) as Boolean) && (it.getValue(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 13 else 0 }))
val RED_MINT = create("red_mint", MintBlock(MintType.RED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MINT_SOUNDS).pushReaction(PushReaction.DESTROY)))
@JvmField
@@ -523,7 +520,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val HEARTY_GRAINS = this.create("hearty_grains", HeartyGrainsBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.PLANT).noCollission().randomTicks().instabreak().sound(CobblemonSounds.VIVICHOKE_SOUNDS)))
@JvmField
val GALARICA_NUT_BUSH = this.create("galarica_nut_bush", NutBushBlock(Properties.of().mapColor(MapColor.PLANT).randomTicks().noCollission().sound(SoundType.SWEET_BERRY_BUSH).pushReaction(PushReaction.DESTROY)))
val GALARICA_NUT_BUSH = this.create("galarica_nut_bush", NutBushBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).randomTicks().noCollission().sound(SoundType.SWEET_BERRY_BUSH).pushReaction(PushReaction.DESTROY)))
@JvmField
val POTTED_RED_APRICORN_SAPLING = this.create("potted_red_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(RED_APRICORN_SAPLING))
@@ -545,9 +542,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val HEARTY_GRAIN_BALE = this.create("hearty_grain_bale", BaleBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).instrument(NoteBlockInstrument.BANJO).strength(0.5F).sound(SoundType.GRASS)))
@JvmField
val TATAMI_BLOCK = this.create("tatami_block", HorizontalRotationalBlock(BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).strength(0.1F).sound(SoundType.GRASS)))
val TATAMI_BLOCK = this.create("tatami_block", HorizontalRotationalBlock(BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).strength(0.1F).sound(SoundType.MOSS_CARPET)))
@JvmField
val TATAMI_MAT = this.create("tatami_mat", HorizontalRotationCarpetBlock(BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).strength(0.1F).sound(SoundType.GRASS)))
val TATAMI_MAT = this.create("tatami_mat", HorizontalRotationCarpetBlock(BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).strength(0.1F).sound(SoundType.MOSS_CARPET)))
/**
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
@@ -559,11 +556,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
APRICORN_LOG to STRIPPED_APRICORN_LOG,
SACCHARINE_WOOD to STRIPPED_SACCHARINE_WOOD,
SACCHARINE_LOG to STRIPPED_SACCHARINE_LOG,
SACCHARINE_HONEY_LOG to STRIPPED_SACCHARINE_LOG
SACCHARINE_LOG_SLATHERED to STRIPPED_SACCHARINE_LOG
)
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(BlockBehaviour.Properties.of().mapColor(apricorn.mapColor()).randomTicks().strength(Blocks.OAK_LOG.defaultDestroyTime(), Blocks.OAK_LOG.explosionResistance).sound(SoundType.WOOD).noOcclusion(), apricorn))
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?) : Block {
@@ -663,7 +658,19 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
Triple(APRICORN_FENCE, 5, 20),
Triple(APRICORN_FENCE_GATE, 5, 20),
Triple(APRICORN_SLAB, 5, 20),
Triple(APRICORN_STAIRS, 5, 20)
Triple(APRICORN_STAIRS, 5, 20),
Triple(SACCHARINE_LOG, 5, 5),
Triple(SACCHARINE_LOG_SLATHERED, 5, 5),
Triple(STRIPPED_SACCHARINE_LOG, 5, 5),
Triple(SACCHARINE_WOOD, 5, 5),
Triple(STRIPPED_SACCHARINE_WOOD, 5, 5),
Triple(SACCHARINE_PLANKS, 5, 20),
Triple(SACCHARINE_LEAVES, 30, 60),
Triple(SACCHARINE_FENCE, 5, 20),
Triple(SACCHARINE_FENCE_GATE, 5, 20),
Triple(SACCHARINE_SLAB, 5, 20),
Triple(SACCHARINE_STAIRS, 5, 20)
).onEach{ data -> setFlammable(data.first, data.second, data.third) }
}
@@ -310,7 +310,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SACCHARINE_LOG = blockItem("saccharine_log", CobblemonBlocks.SACCHARINE_LOG)
@JvmField
val SACCHARINE_HONEY_LOG = blockItem("saccharine_honey_log", CobblemonBlocks.SACCHARINE_HONEY_LOG)
val SACCHARINE_LOG_SLATHERED = blockItem("saccharine_log_slathered", CobblemonBlocks.SACCHARINE_LOG_SLATHERED)
@JvmField
val STRIPPED_SACCHARINE_LOG = blockItem("stripped_saccharine_log", CobblemonBlocks.STRIPPED_SACCHARINE_LOG)
@JvmField
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.mojang.serialization.Codec
@@ -46,6 +47,7 @@ object CobblemonMemories {
val HERD_LEADER = register<String>("herd_leader", PrimitiveCodec.STRING)
/** how many are following me rn? */
val HERD_SIZE = register<Int>("herd_size") // Don't bother saving it, we'll try to keep count roughly.
val ATTACK_TARGET_DATA = register<CobblemonAttackTargetData>("attack_target_data") // This is used to store additional information about the attack target, such as when to give up pursuit.
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
val memoryModule = MemoryModuleType(Optional.of(codec))
@@ -36,6 +36,7 @@ import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureConflictFlagHandler
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
@@ -85,6 +86,7 @@ import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
@@ -140,6 +142,7 @@ import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPack
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
@@ -155,6 +158,7 @@ import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePack
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.SetPastureConflictPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
@@ -166,6 +170,7 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMark
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
@@ -187,6 +192,7 @@ import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
import com.cobblemon.mod.common.net.serverhandling.behaviour.DamageOnCollisionPacketHandler
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
@@ -203,6 +209,7 @@ import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHand
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
import com.cobblemon.mod.common.net.serverhandling.orientation.OrientationPacketHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.SetPastureConflictHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
@@ -213,6 +220,7 @@ import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHan
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
@@ -418,6 +426,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(ClosePasturePacket.ID, ClosePasturePacket::decode, ClosePastureHandler))
list.add(PacketRegisterInfo(PokemonPasturedPacket.ID, PokemonPasturedPacket::decode, PokemonPasturedHandler))
list.add(PacketRegisterInfo(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler))
list.add(PacketRegisterInfo(UpdatePastureConflictFlagPacket.ID, UpdatePastureConflictFlagPacket::decode, UpdatePastureConflictFlagHandler))
// Orientation
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
@@ -528,6 +537,8 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(PasturePokemonPacket.ID, PasturePokemonPacket::decode, PasturePokemonHandler))
list.add(PacketRegisterInfo(UnpasturePokemonPacket.ID, UnpasturePokemonPacket::decode, UnpasturePokemonHandler))
list.add(PacketRegisterInfo(UnpastureAllPokemonPacket.ID, UnpastureAllPokemonPacket::decode, UnpastureAllPokemonHandler))
list.add(PacketRegisterInfo(SetPastureConflictPacket.ID, SetPastureConflictPacket::decode, SetPastureConflictHandler))
// Block entity
list.add(PacketRegisterInfo(AdjustBlockEntityViewerCountPacket.ID, AdjustBlockEntityViewerCountPacket::decode, AdjustBlockEntityViewerCountHandler))
@@ -556,12 +567,14 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
// Cooking
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
// Behaviour Packets
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
list.add(PacketRegisterInfo(DamageOnCollisionPacket.ID, DamageOnCollisionPacket::decode, DamageOnCollisionPacketHandler))
return list
}
@@ -24,23 +24,18 @@ object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Regist
override val resourceKey: ResourceKey<Registry<PoiType>> = Registries.POINT_OF_INTEREST_TYPE
@JvmField
val NURSE_KEY: ResourceKey<PoiType> = createKey("nurse")
val NURSE_KEY = createKey("nurse", CobblemonBlocks.HEALING_MACHINE, 1, 1)
@JvmField
val NURSE = create(NURSE_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.HEALING_MACHINE), 1, 1))
val LURE_CAKE_KEY = createKey("lure_cake", CobblemonBlocks.LURE_CAKE, 0, 1)
@JvmField
val LURE_CAKE_KEY: ResourceKey<PoiType> = createKey("lure_cake")
val SACCHARINE_LOG_SLATHERED_KEY = createKey("saccharine_log_slathered", CobblemonBlocks.SACCHARINE_LOG_SLATHERED, 0, 1)
@JvmField
val LURE_CAKE = create(LURE_CAKE_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.LURE_CAKE), 0, 1))
@JvmField
val SACCHARINE_HONEY_LOG_KEY: ResourceKey<PoiType> = createKey("saccharine_honey_log")
@JvmField
val SACCHARINE_HONEY_LOG = create(SACCHARINE_HONEY_LOG_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.SACCHARINE_HONEY_LOG), 0, 1))
@JvmField
val INCENSE_SWEET_KEY: ResourceKey<PoiType> = createKey("incense_sweet")
@JvmField
val INCENSE_SWEET = create(INCENSE_SWEET_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.INCENSE_SWEET), 0, 1))
val INCENSE_SWEET_KEY = createKey("incense_sweet", CobblemonBlocks.INCENSE_SWEET, 0, 1)
private fun createKey(string: String): ResourceKey<PoiType> = ResourceKey.create(Registries.POINT_OF_INTEREST_TYPE, cobblemonResource(string))
private fun createKey(string: String, block: Block, maxTickets: Int, validRange: Int ): ResourceKey<PoiType> =
ResourceKey.create(Registries.POINT_OF_INTEREST_TYPE, cobblemonResource(string)).also { resourceKey ->
create(resourceKey.location().path, PoiType(getBlockStates(block), maxTickets, validRange))
}
private fun getBlockStates(block: Block): Set<BlockState> = ImmutableSet.copyOf(block.stateDefinition.possibleStates)
}
}
@@ -10,8 +10,11 @@ package com.cobblemon.mod.common.api.ai
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.mojang.serialization.Dynamic
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
import net.minecraft.world.entity.schedule.Activity
import net.minecraft.world.entity.schedule.Schedule
@@ -22,13 +25,30 @@ class BehaviourConfigurationContext {
var coreActivities = setOf(Activity.CORE)
val activities = mutableListOf<ActivityConfigurationContext>()
val schedule = Schedule.EMPTY
val memories = mutableSetOf<MemoryModuleType<*>>()
val sensors = mutableSetOf<SensorType<*>>()
fun getOrCreateActivity(activity: Activity): ActivityConfigurationContext {
return activities.firstOrNull { it.activity == activity } ?: ActivityConfigurationContext(activity).also(activities::add)
}
fun apply(entity: LivingEntity, behaviourConfigs: List<BehaviourConfig>) {
val brain = entity.brain
fun addMemories(vararg memory: MemoryModuleType<*>) {
memories.addAll(memory)
}
fun addMemories(memories: Collection<MemoryModuleType<*>>) {
this.memories.addAll(memories)
}
fun addSensors(vararg sensor: SensorType<*>) {
sensors.addAll(sensor)
}
fun addSensors(sensors: Collection<SensorType<*>>) {
this.sensors.addAll(sensors)
}
fun apply(entity: LivingEntity, behaviourConfigs: List<BehaviourConfig>, dynamic: Dynamic<*>) {
if (entity is MoLangScriptingEntity) {
entity.registerVariables(behaviourConfigs.flatMap { it.getVariables(entity) })
@@ -38,7 +58,11 @@ class BehaviourConfigurationContext {
// Setup the brain config
behaviourConfigs.forEach { it.configure(entity, this) }
var brain = entity.brain
// Apply the brain config
if (entity is MoLangScriptingEntity) {
brain = entity.assignNewBrainWithMemoriesAndSensors(dynamic, memories, sensors)
}
activities.forEach { it.apply(entity) }
brain.setCoreActivities(coreActivities)
brain.setDefaultActivity(defaultActivity)
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.util.asExpression
/**
* This is used in the AI system to store optional additional information about the attack target,
* mainly things like when to give up pursuit, what sort of attacks are permitted, whatever. It's
* a temporary memory, same as ATTACK_TARGET, so relogs will clear it and that's why it has no codec.
*
* To help you get a sense of a use case, imagine a Pidgeotto has an AI task that says it should hunt
* Magikarp that are close to the surface. Once they've found one and chosen them as the attack target,
* they should give up the target if the Magikarp goes too deep, but if it's attacking an entity because
* they attacked its owner, it shouldn't give up on the target for that reason. To address this, when
* hunting Magikarp, the Pidgeotto will set this memory to a CobblemonAttackTargetData with some
* [Expression] that encourages the entity to give up the target if the Magikarp goes too deep.
*
* To make this work, any transition from the FIGHT activity will erase this memory.
*
* @author Hiroku
* @since June 23rd, 2025
*/
class CobblemonAttackTargetData(
/** An expression that returns false when the target is no longer worth attacking. */
val shouldContinue: Expression = "true".asExpression()
)
@@ -15,6 +15,11 @@ import kotlin.jvm.optionals.getOrNull
typealias ExpressionOrEntityVariable = Either<Expression, MoLangConfigVariable>
/**
* In the case of [ExpressionOrEntityVariable] the right side is the only one that requires visibility for a user,
* this function is a shorthand for finding all of the values in the list that have something to show the user to
* potentially edit.
*/
fun List<ExpressionOrEntityVariable>.asVariables() = mapNotNull { it.right().getOrNull() }
@@ -0,0 +1,37 @@
/*
* 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
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* Does nothing except conditionally add some memories and sensors to the brain of the entity.
*
* @author Hiroku
* @since June 27th, 2025
*/
class AddMemoriesAndSensorsConfig : BehaviourConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val memories: Set<MemoryModuleType<*>> = emptySet()
val sensors: Set<SensorType<*>> = mutableSetOf()
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
if (!checkCondition(entity, condition)) return
behaviourConfigurationContext.addMemories(memories)
behaviourConfigurationContext.addSensors(sensors)
}
}
@@ -23,8 +23,8 @@ class AddTasksToActivity : BehaviourConfig {
val activities = mutableListOf<Activity>()
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val tasksByPriority = mutableMapOf<Int, List<TaskConfig>>()
override fun getVariables(entity: LivingEntity) = tasksByPriority.values.flatten().flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
override fun getVariables(entity: LivingEntity) = tasksByPriority.values.flatten().flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
if (!checkCondition(entity, condition)) return
@@ -24,6 +24,7 @@ class ApplyBehaviours : BehaviourConfig {
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
@SerializedName("behaviours", alternate = ["behaviors"])
val behaviours = mutableListOf<ResourceLocation>()
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
return if (checkCondition(entity, condition)) {
behaviours.flatMap {
@@ -44,6 +44,7 @@ interface BehaviourConfig {
cobblemonResource("set_core_activities") to SetCoreActivities::class.java,
cobblemonResource("add_variables") to AddVariablesConfig::class.java,
cobblemonResource("set_variables") to SetVariablesConfig::class.java,
cobblemonResource("add_memories_and_sensors") to AddMemoriesAndSensorsConfig::class.java,
)
}
@@ -21,19 +21,25 @@ import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class CustomScriptBehaviourConfig : BehaviourConfig {
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val variables: List<MoLangConfigVariable> = emptyList()
val script: ExpressionLike = "0".asExpressionLike()
companion object {
val runtime = MoLangRuntime().setup()
}
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val variables: List<MoLangConfigVariable> = emptyList()
val script: ExpressionLike = "0".asExpressionLike()
val memories = emptySet<MemoryModuleType<*>>()
val sensors = emptySet<SensorType<*>>()
override fun getVariables(entity: LivingEntity) = variables
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
if (!checkCondition(entity, condition)) return
behaviourConfigurationContext.addMemories(memories)
behaviourConfigurationContext.addSensors(sensors)
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
runtime.resolve(script)
}
@@ -14,6 +14,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.ai.ActivityConfigurationContext
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
@@ -21,34 +22,42 @@ import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.util.activityRegistry
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import com.mojang.datafixers.util.Pair
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class ScriptBehaviourConfig : BehaviourConfig {
val condition = "true".asExpressionLike()
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val script = cobblemonResource("dummy")
val variables = mutableListOf<MoLangConfigVariable>()
val memories = emptySet<MemoryModuleType<*>>()
val sensors = emptySet<SensorType<*>>()
override fun getVariables(entity: LivingEntity) = variables
override fun configure(entity: LivingEntity, context: BehaviourConfigurationContext) {
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
if (!checkCondition(entity, condition)) return
val runtime = MoLangRuntime().setup()
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!runtime.resolveBoolean(condition)) return
val struct = createBrainStruct(entity, context)
val struct = createBrainStruct(entity, behaviourConfigurationContext)
val script = CobblemonScripts.scripts[this.script]
?: run {
Cobblemon.LOGGER.error("Tried loading script $script as part of an entity brain but that script does not exist")
return
}
behaviourConfigurationContext.addMemories(memories)
behaviourConfigurationContext.addSensors(sensors)
runtime.resolve(script, mapOf("brain" to struct))
}
@@ -15,6 +15,7 @@ import net.minecraft.world.entity.schedule.Activity
class SetDefaultActivity : BehaviourConfig {
val activity: Activity = Activity.IDLE
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
behaviourConfigurationContext.defaultActivity = activity
@@ -23,7 +23,6 @@ class SetVariablesConfig : BehaviourConfig {
var variableValues = mutableMapOf<String, ExpressionLike>()
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
val runtime = MoLangRuntime().setup()
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
@@ -15,8 +15,6 @@ import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WANDER
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
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.PokemonMoveControl
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.withQueryValue
@@ -50,6 +48,7 @@ class AirWanderTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.WALK_TARGET, MemoryModuleType.LOOK_TARGET, CobblemonMemories.PATH_COOLDOWN)
val wanderChanceExpression = wanderChance.asSimplifiedExpression(entity)
return BehaviorBuilder.create {
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
@@ -23,19 +21,14 @@ class AllOfTaskConfig : TaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val tasks: List<TaskConfig> = emptyList()
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
return if (checkCondition(entity, condition))
tasks.flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
else
listOf(condition).asVariables()
}
override fun getVariables(entity: LivingEntity) = tasks.flatMap { it.getVariables(entity) }
override fun createTasks(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): List<BehaviorControl<in LivingEntity>> {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return emptyList()
return tasks.flatMap { it.createTasks(entity, behaviourConfigurationContext) }
}
}
@@ -8,24 +8,21 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.ai.AttackAngryAtTask
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class AttackAngryAtTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "should_attack_angry_at", true).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.ANGRY_AT, MemoryModuleType.ATTACK_TARGET, CobblemonMemories.POKEMON_SLEEPING)
return AttackAngryAtTask.create()
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.AttackHostileMobsTask
import com.mojang.serialization.Codec
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class AttackHostileMobsTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
return emptyList<MoLangConfigVariable>()
}
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
return AttackHostileMobsTask.create()
}
companion object {
val CODEC: Codec<AttackHostileMobsTaskConfig> = Codec.unit(AttackHostileMobsTaskConfig())
}
}
@@ -12,22 +12,31 @@ import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.VillagerCalmDown
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class CalmDownTaskConfig : SingleTaskConfig {
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(
MemoryModuleType.HURT_BY,
MemoryModuleType.HURT_BY_ENTITY,
MemoryModuleType.NEAREST_HOSTILE,
)
behaviourConfigurationContext.addSensors(SensorType.VILLAGER_HOSTILES)
return VillagerCalmDown.create()
}
}
@@ -24,6 +24,7 @@ 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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* Checks nearby entities and counts how many have nominated this entity as their leader.
@@ -44,6 +45,12 @@ class CountFollowersTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val checkTicksValue = checkTicks.resolveInt()
behaviourConfigurationContext.addMemories(
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
CobblemonMemories.HERD_SIZE,
CobblemonMemories.HERD_LEADER
)
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
return BehaviorBuilder.create { instance ->
instance.group(
instance.present(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES),
@@ -55,9 +62,15 @@ class CountFollowersTaskConfig : SingleTaskConfig {
}
val myUUID = entity.uuid.toString()
val followersCount = instance.get(nearbyEntities).findAll {
it is PokemonEntity && it.brain.getMemory(CobblemonMemories.HERD_LEADER).getOrNull() == myUUID
it is PokemonEntity
&& it.brain.hasMemoryValue(CobblemonMemories.HERD_LEADER)
&& it.brain.getMemory(CobblemonMemories.HERD_LEADER).getOrNull() == myUUID
}.count()
herdCount.set(followersCount)
if (followersCount == 0) {
herdCount.erase()
} else {
herdCount.set(followersCount)
}
return@Trigger true
}
}
@@ -23,7 +23,7 @@ class DoNothingTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val minDurationTicks: ExpressionOrEntityVariable = Either.left("40".asExpression())
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(condition, minDurationTicks, maxDurationTicks).asVariables()
override fun getVariables(entity: LivingEntity) = listOf(minDurationTicks, maxDurationTicks).asVariables()
override fun createTask(
entity: LivingEntity,
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
@@ -16,6 +17,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.EatGrassTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class EatGrassTaskConfig : SingleTaskConfig {
companion object {
@@ -47,6 +49,8 @@ class EatGrassTaskConfig : SingleTaskConfig {
return null
}
behaviourConfigurationContext.addMemories(MemoryModuleType.WALK_TARGET, CobblemonMemories.RECENTLY_ATE_GRASS)
return WrapperLivingEntityTask(
EatGrassTask(
chance,
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.CobblemonSensors
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
@@ -21,6 +22,7 @@ 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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
var condition = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, "exit_battle_when_hurt", true).asExpressible()
@@ -36,10 +38,19 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val includePassiveDamage = includePassiveDamage.resolveBoolean()
if (!condition.resolveBoolean()) return null
val includePassiveDamage = includePassiveDamage.resolveBoolean()
behaviourConfigurationContext.addMemories(
MemoryModuleType.HURT_BY,
MemoryModuleType.HURT_BY_ENTITY
)
behaviourConfigurationContext.addSensors(SensorType.HURT_BY)
if (entity is NPCEntity) {
behaviourConfigurationContext.addMemories(CobblemonMemories.NPC_BATTLING)
behaviourConfigurationContext.addSensors(CobblemonSensors.NPC_BATTLING)
fun cancelNPCBattles(npcEntity: NPCEntity): Boolean {
val battles = npcEntity.battleIds.mapNotNull(BattleRegistry::getBattle)
battles.forEach { it.end() }
@@ -58,6 +69,7 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
}
}
} else if (entity is PokemonEntity) {
behaviourConfigurationContext.addMemories(CobblemonMemories.POKEMON_BATTLE)
fun cancelPokemonBattle(pokemonEntity: PokemonEntity): Boolean {
val battle = BattleRegistry.getBattle(pokemonEntity.battleId ?: return false)
battle?.end()
@@ -43,6 +43,10 @@ class FindAirTaskConfig : SingleTaskConfig {
if (entity !is PathfinderMob) {
return null
}
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
CobblemonMemories.PATH_COOLDOWN
)
return BehaviorBuilder.create {
it.group(
it.absent(MemoryModuleType.WALK_TARGET),
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangV
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.ai.ToleratedHerdLeader
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
@@ -24,8 +25,58 @@ 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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities
import net.minecraft.world.entity.ai.sensing.SensorType
class FindHerdLeaderTaskConfig : SingleTaskConfig {
companion object {
/**
* Logic used to choose the best herd leader from nearby visible entities.
*
* - Higher tier leaders are always preferred.
* - Same-tier leaders that are closer are preferred except for when they're the same tier as the current leader.
* - We don't want to exceed the target's herd size limit.
* - We don't want to choose a leader that is themselves following a leader.
* - Some leader definitions allow lower-level Pokémon to lead them.
* - Leaders just have to not be in a party - pastured and wild Pokémon can mingle.
*/
fun getBestHerdLeader(
currentLeader: Pair<PokemonEntity, ToleratedHerdLeader>?,
nearbyEntities: NearestVisibleLivingEntities,
entity: PokemonEntity
): PokemonEntity? {
var bestLeader: PokemonEntity? = null
val (currentLeaderEntity, currentLeaderDefinition) = currentLeader ?: Pair(null, null)
var bestTier = currentLeaderDefinition?.tier?.let { it + 1 } ?: 0 // Only upgrade to a higher tier leader
var bestDistance = Float.MAX_VALUE
nearbyEntities.findAll {
it is PokemonEntity &&
it != currentLeader &&
it.pokemon.storeCoordinates.get()?.store !is PartyStore &&
it.getHerdSize() < it.behaviour.herd.maxSize
}.forEach { possibleLeader ->
possibleLeader as PokemonEntity
val matchingHerdLeader = entity.behaviour.herd.bestMatchLeader(entity, possibleLeader) ?: return@forEach
val alreadyIsALeader = possibleLeader.brain.hasMemoryValue(CobblemonMemories.HERD_SIZE)
val nestedHerdTier = currentLeaderEntity?.getHerdTier() ?: 0
if (nestedHerdTier >= matchingHerdLeader.tier) {
return@forEach // This leader is following a leader of a higher tier, we can't replace them
}
val distance = entity.distanceTo(possibleLeader)
if (matchingHerdLeader.tier < bestTier) {
return@forEach // No need to check further if this leader is worse than the best found so far
} else if ((distance > bestDistance && !alreadyIsALeader) && matchingHerdLeader.tier == bestTier) {
return@forEach // No need to check further if this leader is farther than the best found so far, unless they are already a leader - I'd prefer to join a pack
} else {
bestLeader = possibleLeader
bestDistance = distance
bestTier = matchingHerdLeader.tier
}
}
return bestLeader ?: currentLeaderEntity
}
}
// How frequently to check for whether it should herd. Probably isn't that expensive but might use this for chance.
val checkTicks: ExpressionOrEntityVariable = Either.left("60".asExpression())
@@ -41,40 +92,33 @@ class FindHerdLeaderTaskConfig : SingleTaskConfig {
return null
}
behaviourConfigurationContext.addMemories(
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
CobblemonMemories.HERD_LEADER,
MemoryModuleType.WALK_TARGET
)
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val checkTicksValue = checkTicks.resolveInt()
return BehaviorBuilder.create { instance ->
instance.group(
instance.present(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES),
instance.absent(CobblemonMemories.HERD_LEADER),
instance.absent(MemoryModuleType.WALK_TARGET)
).apply(instance) { nearbyEntities, herdLeader, _ ->
instance.absent(CobblemonMemories.HERD_LEADER)
).apply(instance) { nearbyEntities, herdLeader ->
Trigger { world, entity, _ ->
if (world.gameTime % checkTicksValue != 0L) {
return@Trigger false
}
entity as PokemonEntity
val toleratedLeaders = entity.behaviour.herd.toleratedLeaders
val nearbyLeaders = instance.get(nearbyEntities).findAll {
it is PokemonEntity &&
it.pokemon.storeCoordinates.get()?.store !is PartyStore &&
it.exposedSpecies.resourceIdentifier in toleratedLeaders &&
!it.brain.hasMemoryValue(CobblemonMemories.HERD_LEADER) &&
it.pokemon.level >= entity.pokemon.level
}.toList()
val bestLeader = getBestHerdLeader(
currentLeader = null,
nearbyEntities = instance.get(nearbyEntities),
entity = entity
) ?: return@Trigger false
if (nearbyLeaders.isEmpty()) {
return@Trigger false
}
val leader = nearbyLeaders
.filterIsInstance<PokemonEntity>()
.filter { it.getHerdSize() < entity.behaviour.herd.maxSize }
.maxByOrNull { it.pokemon.level }
?: return@Trigger false
herdLeader.set(leader.uuid.toString())
herdLeader.set(bestLeader.uuid.toString())
bestLeader.brain.eraseMemory(CobblemonMemories.HERD_LEADER)
return@Trigger true
}
}
@@ -8,6 +8,8 @@
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.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
@@ -18,6 +20,7 @@ import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class FindRestingPlaceTaskConfig : SingleTaskConfig {
val horizontalSearchDistance: ExpressionOrEntityVariable = Either.left("16".asExpression())
@@ -28,6 +31,13 @@ class FindRestingPlaceTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(
CobblemonMemories.PATH_COOLDOWN,
CobblemonMemories.POKEMON_DROWSY,
MemoryModuleType.WALK_TARGET
)
behaviourConfigurationContext.addSensors(CobblemonSensors.POKEMON_DROWSY)
return WrapperLivingEntityTask(
FindRestingPlaceTask.create(horizontalSearchDistance.resolveInt(), verticalSearchDistance.resolveInt()),
PokemonEntity::class.java
@@ -20,6 +20,7 @@ import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class FleeAttackerTaskConfig : SingleTaskConfig {
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_attacker", true).asExpressible()
@@ -38,6 +39,10 @@ class FleeAttackerTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.WALK_TARGET)
behaviourConfigurationContext.addSensors(SensorType.HURT_BY)
val speedMultiplier = speedMultiplier.resolveFloat()
val desiredDistance = desiredDistance.resolveInt()
return WrapperLivingEntityTask(
@@ -20,6 +20,7 @@ import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class FleeNearestHostileTaskConfig : SingleTaskConfig {
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_nearest_hostile", true).asExpressible()
@@ -34,6 +35,8 @@ class FleeNearestHostileTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.NEAREST_HOSTILE, MemoryModuleType.WALK_TARGET)
behaviourConfigurationContext.addSensors(SensorType.VILLAGER_HOSTILES)
val speedMultiplier = speedMultiplier.resolveFloat()
val desiredDistance = desiredDistance.resolveInt()
return WrapperLivingEntityTask(
@@ -23,6 +23,7 @@ import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class FlyInCirclesTaskConfig : SingleTaskConfig {
val poseTypes: Set<PoseType> = setOf(
@@ -31,7 +32,7 @@ class FlyInCirclesTaskConfig : SingleTaskConfig {
)
val minAngularVelocityDegrees = numberVariable(WANDER, "min_fly_circling_angular_velocity", 0.0).asExpressible()
val maxAngularVelocityDegrees = numberVariable(WANDER, "max_fly_circling_angular_velocity", 2.0).asExpressible()
val maxAngularVelocityDegrees = numberVariable(WANDER, "max_fly_circling_angular_velocity", 1.0).asExpressible()
val speed = numberVariable(WANDER, "fly_circling_speed", 0.6).asExpressible()
val verticalSpeed: ExpressionOrEntityVariable = Either.left("0.0".asExpression())
val minDurationTicks: ExpressionOrEntityVariable = Either.left("60".asExpression())
@@ -55,6 +56,7 @@ class FlyInCirclesTaskConfig : SingleTaskConfig {
if (entity !is PokemonEntity) {
return null
}
behaviourConfigurationContext.addMemories(MemoryModuleType.WALK_TARGET, MemoryModuleType.PATH)
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
return CircleAroundTask(
poseTypes = poseTypes,
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask.Companion.wrapped
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
@@ -15,16 +16,22 @@ import com.cobblemon.mod.common.entity.ai.FollowHerdLeaderTask
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class FollowHerdLeaderTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
return listOf() // TODO add tooFar and closeEnough variables
return listOf()
}
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
if (entity !is PokemonEntity) {
return null
}
behaviourConfigurationContext.addMemories(CobblemonMemories.HERD_LEADER, MemoryModuleType.WALK_TARGET)
return FollowHerdLeaderTask().wrapped<PokemonEntity>()
}
}
@@ -20,6 +20,7 @@ import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class FollowWalkTargetTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
@@ -30,6 +31,7 @@ class FollowWalkTargetTaskConfig : SingleTaskConfig {
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
behaviourConfigurationContext.addMemories(MemoryModuleType.WALK_TARGET, MemoryModuleType.PATH, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)
return WrapperLivingEntityTask(
FollowWalkTargetTask(minRunTicks.resolveInt(), maxRunTicks.resolveInt()),
PathfinderMob::class.java
@@ -16,6 +16,8 @@ import com.cobblemon.mod.common.entity.ai.GetAngryAtAttackerTask
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class GetAngryAtAttackerTaskConfig : SingleTaskConfig {
companion object {
@@ -32,6 +34,11 @@ class GetAngryAtAttackerTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(
MemoryModuleType.HURT_BY_ENTITY,
MemoryModuleType.ANGRY_AT,
)
behaviourConfigurationContext.addSensors(SensorType.HURT_BY)
return GetAngryAtAttackerTask.create()
}
}
@@ -8,6 +8,8 @@
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.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
@@ -18,6 +20,8 @@ import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class GoToHealingMachineTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SELF_HEALING, USE_HEALING_MACHINES, true).asExpressible()
@@ -39,7 +43,12 @@ class GoToHealingMachineTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
MemoryModuleType.LOOK_TARGET,
CobblemonMemories.NPC_BATTLING
)
behaviourConfigurationContext.addSensors(CobblemonSensors.NPC_BATTLING)
return GoToHealingMachineTask.create(
horizontalSearchRange = horizontalSearchRange.asExpression(),
verticalSearchRange = verticalSearchRange.asExpression(),
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.OmniPathingEntity
import com.cobblemon.mod.common.util.closestPosition
import kotlin.math.ceil
import kotlin.math.floor
@@ -43,7 +44,10 @@ class GoToLandTaskConfig : SingleTaskConfig {
if (entity !is PathfinderMob) {
return null
}
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
CobblemonMemories.PATH_COOLDOWN
)
return BehaviorBuilder.create {
it.group(
it.absent(MemoryModuleType.WALK_TARGET),
@@ -56,6 +60,8 @@ class GoToLandTaskConfig : SingleTaskConfig {
entity as PathfinderMob
val walkSpeedValue = walkSpeed.resolveFloat()
val iterable = BlockPos.betweenClosed(
Mth.floor(entity.x - 8.0),
entity.blockY,
@@ -71,7 +77,7 @@ class GoToLandTaskConfig : SingleTaskConfig {
isSafeLandPosAround(entity.level() as ServerLevel, it, entity)
} ?: return@Trigger false
walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 1))
walkTarget.set(WalkTarget(blockPos.above(), walkSpeedValue, 0))
return@Trigger true
}
}
@@ -82,7 +88,7 @@ class GoToLandTaskConfig : SingleTaskConfig {
val blockState = world.getBlockState(pos)
val isFluid = world.getFluidState(pos.above()).isEmpty.not()
val solidBelow = blockState.isSolid
val solidBelow = blockState.isSolid || (mob is OmniPathingEntity && mob.canFly())
if (isFluid || !solidBelow) {
return false
@@ -8,6 +8,8 @@
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
@@ -15,6 +17,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.GoToSleepTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class GoToSleepTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
@@ -22,6 +25,15 @@ class GoToSleepTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
if (entity !is PokemonEntity) {
return null
}
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
CobblemonMemories.POKEMON_DROWSY,
CobblemonMemories.POKEMON_SLEEPING
)
behaviourConfigurationContext.addSensors(CobblemonSensors.POKEMON_DROWSY)
return WrapperLivingEntityTask(GoToSleepTask.create(), PokemonEntity::class.java)
}
}
@@ -0,0 +1,67 @@
/*
* 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.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* Immediately gets angry at the nearest visible entity that matches the [entityCondition] and is within the [range].
*
* @author Hiroku
* @since June 23rd, 2025
*/
class HateEntityTaskConfig : SingleTaskConfig {
val entityCondition: Expression = "true".asExpression()
val range: ExpressionOrEntityVariable = Either.left("24".asExpression())
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
val range = range.resolveFloat()
behaviourConfigurationContext.addMemories(
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
MemoryModuleType.ANGRY_AT
)
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
return BehaviorBuilder.create { instance ->
instance.group(
instance.present(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES),
instance.registered(MemoryModuleType.ANGRY_AT)
).apply(instance) { entities, angryAt ->
Trigger { world, entity, _ ->
val target = instance.get(entities).findClosest {
runtime.withQueryValue("entity", it.asMostSpecificMoLangValue())
return@findClosest runtime.resolveBoolean(entityCondition)
}.orElse(null)
if (target != null && target.distanceTo(entity) <= range) {
angryAt.set(target.uuid)
}
return@Trigger true
}
}
}
}
}
@@ -8,6 +8,8 @@
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.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
@@ -20,6 +22,7 @@ import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class HealUsingHealingMachineTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SELF_HEALING, USE_HEALING_MACHINES, true).asExpressible()
@@ -34,6 +37,8 @@ class HealUsingHealingMachineTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.WALK_TARGET, CobblemonMemories.NPC_BATTLING,)
behaviourConfigurationContext.addSensors(CobblemonSensors.NPC_BATTLING)
return HealUsingHealingMachineTask(horizontalUseRange.asExpression(), verticalUseRange.asExpression())
}
}
@@ -8,6 +8,8 @@
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.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
@@ -18,6 +20,7 @@ import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class LookAtBattlingPokemonTaskConfig : SingleTaskConfig {
companion object {
@@ -40,6 +43,11 @@ class LookAtBattlingPokemonTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!resolveBooleanVariable(LOOK_AT_BATTLING_POKEMON)) return null
behaviourConfigurationContext.addMemories(
MemoryModuleType.LOOK_TARGET,
CobblemonMemories.BATTLING_POKEMON
)
behaviourConfigurationContext.addSensors(CobblemonSensors.BATTLING_POKEMON)
return LookAtBattlingPokemonTask.create(
minDurationTicks = minDurationTicks.resolveInt(),
maxDurationTicks = maxDurationTicks.resolveInt()
@@ -16,6 +16,8 @@ import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
class LookAtEntitiesTaskConfig : SingleTaskConfig {
companion object {
@@ -36,6 +38,8 @@ class LookAtEntitiesTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.LOOK_TARGET)
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
return SetEntityLookTarget.create(maxDistance.resolveFloat())
}
}
@@ -8,15 +8,19 @@
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.npc.ai.LookAtSpeakerTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class LookAtSpeakerTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
) = LookAtSpeakerTask.create()
) = LookAtSpeakerTask.create().also {
behaviourConfigurationContext.addMemories(MemoryModuleType.LOOK_TARGET, CobblemonMemories.DIALOGUES)
}
}
@@ -20,6 +20,7 @@ import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.LookAtTargetSink
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class LookAtTargetTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
@@ -38,6 +39,7 @@ class LookAtTargetTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.LOOK_TARGET)
return WrapperLivingEntityTask(LookAtTargetSink(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt()), Mob::class.java)
}
}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
@@ -15,13 +16,22 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.LookAtTargetedBattlePokemonTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class LookAtTargetedBattlePokemonTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity> {
): BehaviorControl<in LivingEntity>? {
if (entity !is PokemonEntity) {
return null
}
behaviourConfigurationContext.addMemories(
CobblemonMemories.POKEMON_BATTLE,
CobblemonMemories.TARGETED_BATTLE_POKEMON,
MemoryModuleType.LOOK_TARGET,
)
return WrapperLivingEntityTask(LookAtTargetedBattlePokemonTask.create(), PokemonEntity::class.java)
}
}
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.LOOKING_CATEGORY
import com.cobblemon.mod.common.entity.ai.LookInDirectionTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class LookInDirectionTaskConfig : SingleTaskConfig {
var condition = booleanVariable(LOOKING_CATEGORY, "locked_rotation", true).asExpressible()
@@ -32,5 +33,7 @@ class LookInDirectionTaskConfig : SingleTaskConfig {
shouldLock = condition.asExpression(),
yaw = yaw.asExpression(),
pitch = pitch.asExpression()
)
).also {
behaviourConfigurationContext.addMemories(MemoryModuleType.LOOK_TARGET)
}
}
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
@@ -25,6 +24,7 @@ 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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* Task that looks around for a better herd leader or gives up on a leader
@@ -48,6 +48,11 @@ class MaintainHerdLeaderTaskConfig : SingleTaskConfig {
if (entity !is PokemonEntity) {
return null
}
behaviourConfigurationContext.addMemories(
CobblemonMemories.HERD_LEADER,
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
)
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val checkTicks = checkTicks.resolveInt()
return BehaviorBuilder.create { instance ->
@@ -62,26 +67,22 @@ class MaintainHerdLeaderTaskConfig : SingleTaskConfig {
}
val leader = instance.get(herdLeader).let(UUID::fromString).let(world::getEntity) as? PokemonEntity
if (leader == null) {
val currentLeaderDefinition = leader?.let { leader ->
entity.behaviour.herd.toleratedLeaders.find { it.pokemon.matches(leader) }
}
if (leader == null || currentLeaderDefinition == null) {
entity.brain.eraseMemory(CobblemonMemories.HERD_LEADER)
return@Trigger true // No leader, so we erase the memory
} else if (leader.brain.hasMemoryValue(CobblemonMemories.HERD_LEADER)) {
entity.brain.eraseMemory(CobblemonMemories.HERD_LEADER)
return@Trigger true
} else if (leader.exposedSpecies.resourceIdentifier !in entity.behaviour.herd.toleratedLeaders) {
// Zoroark getting exposed then herd members pausing and saying "hey wait a minute"
entity.brain.eraseMemory(CobblemonMemories.HERD_LEADER)
} else {
val bestSurroundingLeader = instance.get(nearbyEntities).findAll {
it is PokemonEntity &&
it != leader &&
it.pokemon.storeCoordinates.get()?.store !is PartyStore &&
it.exposedSpecies.resourceIdentifier in entity.behaviour.herd.toleratedLeaders &&
!it.brain.hasMemoryValue(CobblemonMemories.HERD_LEADER) &&
it.pokemon.level > leader.pokemon.level // Has to be a superior leader to the existing one
}.maxByOrNull { (it as PokemonEntity).pokemon.level } as? PokemonEntity
if (bestSurroundingLeader != null) {
entity.brain.setMemory(CobblemonMemories.HERD_LEADER, bestSurroundingLeader.uuid.toString())
val bestLeader = FindHerdLeaderTaskConfig.getBestHerdLeader(
currentLeader = (leader to currentLeaderDefinition),
nearbyEntities = instance.get(nearbyEntities),
entity = entity
)
if (bestLeader != null && bestLeader != leader) {
bestLeader.brain.eraseMemory(CobblemonMemories.HERD_LEADER)
entity.brain.setMemory(CobblemonMemories.HERD_LEADER, bestLeader.uuid.toString())
}
}
return@Trigger true
@@ -89,5 +90,4 @@ class MaintainHerdLeaderTaskConfig : SingleTaskConfig {
}
}
}
}
@@ -8,22 +8,16 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.MeleeAttackTask
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.BattleFlightTask
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.ManageFlightInBattleTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class BattleFlightTaskConfig : SingleTaskConfig {
class ManageFlightInBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
@@ -31,6 +25,7 @@ class BattleFlightTaskConfig : SingleTaskConfig {
if (entity !is PokemonEntity) {
return null
}
return BattleFlightTask.create()
behaviourConfigurationContext.addMemories(CobblemonMemories.POKEMON_BATTLE)
return ManageFlightInBattleTask.create()
}
}
@@ -15,11 +15,12 @@ import com.cobblemon.mod.common.entity.npc.ai.MeleeAttackTask
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class MeleeAttackTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacks_melee", true).asExpressible()
val range = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_range", 1.5F).asExpressible()
val cooldownTicks = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_cooldown", 30).asExpressible()
val cooldownTicks = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_cooldown", 20).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
@@ -33,7 +34,10 @@ class MeleeAttackTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(
MemoryModuleType.ATTACK_TARGET,
MemoryModuleType.ATTACK_COOLING_DOWN
)
return MeleeAttackTask.create(
range = range.asExpression(),
cooldownTicks = cooldownTicks.asExpression()
@@ -63,6 +63,10 @@ class MoveIntoFluidTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
CobblemonMemories.PATH_COOLDOWN
)
val movesIntoWater = this@MoveIntoFluidTaskConfig.movesIntoWater.resolveBoolean()
val movesIntoLava = movesIntoLava.resolveBoolean()
val speedModifier = speedModifier.resolveFloat()
@@ -15,10 +15,11 @@ import com.cobblemon.mod.common.entity.ai.MoveToAttackTargetTask
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class MoveToAttackTargetTaskConfig : SingleTaskConfig {
val speedMultiplier = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacking_movement_speed", 0.5).asExpressible()
val closeEnoughDistance: ExpressionOrEntityVariable = Either.left("1".asExpression())
val closeEnoughDistance: ExpressionOrEntityVariable = Either.left("0".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(
speedMultiplier,
@@ -31,5 +32,10 @@ class MoveToAttackTargetTaskConfig : SingleTaskConfig {
) = MoveToAttackTargetTask.create(
speedMultiplier = speedMultiplier.asExpression(),
closeEnoughDistance = closeEnoughDistance.asExpression()
)
).also {
behaviourConfigurationContext.addMemories(
MemoryModuleType.ATTACK_TARGET,
MemoryModuleType.WALK_TARGET
)
}
}
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class MoveToOwnerTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
@@ -38,6 +39,10 @@ class MoveToOwnerTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
MemoryModuleType.LOOK_TARGET
)
return WrapperLivingEntityTask(
MoveToOwnerTask.create(
condition = condition.asExpression(),
@@ -9,12 +9,12 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.toDF
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.RunOne
@@ -35,14 +35,14 @@ class OneOfTaskConfig : SingleTaskConfig {
val task: TaskConfig = SingleTaskConfig.nothing()
}
val condition: ExpressionLike = "true".asExpressionLike()
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val options = mutableListOf<OneOfTaskOption>()
override fun getVariables(entity: LivingEntity) = options.flatMap { it.task.getVariables(entity) }
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!runtime.resolveBoolean(condition)) return null
if (!condition.resolveBoolean()) return null
return RunOne(options.map { it.task.createTasks(entity, behaviourConfigurationContext).first() toDF it.weight })
}
}
@@ -22,6 +22,7 @@ import net.minecraft.world.phys.Vec3
class PointToSpawnTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET)
return BehaviorBuilder.create {
it.group(
it.registered(MemoryModuleType.LOOK_TARGET),
@@ -188,7 +188,7 @@ The 'look_in_direction' type creates a task that will make the entity look in a
### move_to_owner
The 'move_to_owner' type creates a task that will make the entity move to its owner. This will only work for entities that
can be owned, like Pokémon.
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if this entire task should exist on the entity or not. This runs at the time of entity creation, not on tick.
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the entity should move to its owner this tick. Defaults to true.
- `completionRange`: A MoLang expression that determines the distance from the owner that the entity needs to be for the path to be considered complete. Defaults to 4.
- `speedMultiplier`: A MoLang expression that determines the speed multiplier for moving to the owner. Defaults to 0.4 which is slightly above the normal walk speed.
- `teleportDistance`: A MoLang expression that determines the distance from the owner the entity must be before it resorts to teleporting. A value of -1 will cause it to never teleport. Defaults to 24.
@@ -9,12 +9,16 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.weightedSelection
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -35,17 +39,16 @@ class RandomTaskConfig : TaskConfig {
val task: TaskConfig = SingleTaskConfig.nothing()
}
val condition: ExpressionLike = "true".asExpressionLike()
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val choices = mutableListOf<RandomTaskChoice>()
override fun getVariables(entity: LivingEntity) = choices.flatMap { it.task.getVariables(entity) }
override fun getVariables(entity: LivingEntity) = choices.flatMap { it.task.getVariables(entity) } + listOf(condition).asVariables()
override fun createTasks(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): List<BehaviorControl<in LivingEntity>> {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!runtime.resolveBoolean(condition)) return emptyList()
if (!condition.resolveBoolean()) return emptyList()
val task = choices.weightedSelection { it.weight }?.task ?: throw IllegalStateException("No tasks to choose from in random_task config")
return task.createTasks(entity, behaviourConfigurationContext)
}
@@ -21,6 +21,7 @@ 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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* Runs a registered MoLang script (from the molang datapack folder) each tick.
@@ -38,6 +39,8 @@ class RunScript : SingleTaskConfig {
val script = stringVariable(SCRIPT_CATEGORY, "script", "cobblemon:dummy_script").asExpressible()
val variables = mutableListOf<MoLangConfigVariable>()
val memories = emptySet<MemoryModuleType<*>>()
val sensors = emptySet<SensorType<*>>()
override fun getVariables(entity: LivingEntity) = listOf(script).asVariables() + variables
@@ -45,6 +48,8 @@ class RunScript : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? = BehaviorBuilder.create {
behaviourConfigurationContext.addMemories(memories + MemoryModuleType.LOOK_TARGET)
behaviourConfigurationContext.addSensors(sensors)
it.group(
it.registered(MemoryModuleType.LOOK_TARGET) // I think I need to have at least something here?
).apply(it) { _ ->
@@ -25,6 +25,10 @@ class SleepIfOnTrainerBedTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity> {
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
CobblemonMemories.POKEMON_SLEEPING
)
return BehaviorBuilder.create {
it.group(
it.registered(MemoryModuleType.WALK_TARGET),
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
@@ -22,14 +23,11 @@ class StayAfloatTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SharedEntityVariables.MOVEMENT_CATEGORY, "can_float", true).asExpressible()
val chance = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, "float_chance", 0.8F).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
chance
).asVariables()
override fun getVariables(entity: LivingEntity) = listOf(condition, chance).asVariables()
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(CobblemonMemories.POKEMON_BATTLE)
return WrapperLivingEntityTask(
StayAfloatTask(chance.resolveFloat()),
PathfinderMob::class.java
@@ -0,0 +1,50 @@
/*
* 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.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask.Companion.wrapped
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import java.util.function.Predicate
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.StopAttackingIfTargetInvalid
import net.minecraft.world.entity.ai.memory.MemoryModuleType
/**
* A task config wrapping around vanilla's [StopAttackingIfTargetInvalid] that supports the optional ATTACK_TARGET_DATA
* memory to determine if the target is still valid for attacking.
*
* @author Hiroku
* @since June 23rd, 2025
*/
class StopAttackingIfTargetInvalidTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
val runtime = MoLangRuntime().setup()
behaviourConfigurationContext.addMemories(CobblemonMemories.ATTACK_TARGET_DATA, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)
return StopAttackingIfTargetInvalid.create<Mob>(
Predicate { target ->
val targetData = entity.brain.getMemory(CobblemonMemories.ATTACK_TARGET_DATA).orElse(null) ?: return@Predicate false
runtime.withQueryValue("entity", target.asMostSpecificMoLangValue())
return@Predicate !runtime.resolveBoolean(targetData.shouldContinue)
}
).wrapped()
}
}
@@ -15,18 +15,19 @@ import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.StopBeingAngryIfTargetDead
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class StopBeingAngryIfAttackerDeadTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "stop_being_angry_if_attacker_dead", true).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.ANGRY_AT)
return StopBeingAngryIfTargetDead.create()
}
}
@@ -29,5 +29,7 @@ class SwitchFromActionEffectTaskConfig : SingleTaskConfig {
return@Trigger true
}
}
}.also {
behaviourConfigurationContext.addMemories(CobblemonMemories.ACTIVE_ACTION_EFFECT)
}
}
@@ -29,5 +29,7 @@ class SwitchFromChattingTaskConfig : SingleTaskConfig {
return@Trigger true
}
}
}.also {
behaviourConfigurationContext.addMemories(CobblemonMemories.DIALOGUES)
}
}
@@ -8,6 +8,7 @@
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 net.minecraft.world.entity.LivingEntity
@@ -25,9 +26,12 @@ class SwitchFromFightTaskConfig : SingleTaskConfig {
it.absent(MemoryModuleType.ATTACK_TARGET)
).apply(it) { _ ->
Trigger { level, entity, _ ->
entity.brain.eraseMemory(CobblemonMemories.ATTACK_TARGET_DATA)
entity.brain.updateActivityFromSchedule(level.dayTime, level.gameTime)
return@Trigger true
}
}
}.also {
behaviourConfigurationContext.addMemories(MemoryModuleType.ATTACK_TARGET)
}
}
@@ -22,6 +22,7 @@ class SwitchFromHerdTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(CobblemonMemories.HERD_LEADER)
return BehaviorBuilder.create {
it.group(
it.absent(CobblemonMemories.HERD_LEADER)
@@ -22,6 +22,7 @@ class SwitchFromNPCBattleTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(CobblemonMemories.NPC_BATTLING)
return BehaviorBuilder.create {
it.group(it.absent(CobblemonMemories.NPC_BATTLING)).apply(it) { _ ->
Trigger { level, entity, _ ->
@@ -22,6 +22,7 @@ class SwitchFromPokemonBattleTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(CobblemonMemories.POKEMON_BATTLE)
return BehaviorBuilder.create {
it.group(it.absent(CobblemonMemories.POKEMON_BATTLE)).apply(it) { _ ->
Trigger { level, entity, _ ->
@@ -29,6 +29,7 @@ class SwitchFromSleepOnTrainerBedTaskConfig : SingleTaskConfig {
return null
}
behaviourConfigurationContext.addMemories(CobblemonMemories.POKEMON_SLEEPING)
return BehaviorBuilder.create {
it.group(
it.registered(CobblemonMemories.POKEMON_SLEEPING)
@@ -23,6 +23,7 @@ class SwitchToActionEffectTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(CobblemonMemories.ACTIVE_ACTION_EFFECT)
return BehaviorBuilder.create {
it.group(
it.absent(CobblemonMemories.ACTIVE_ACTION_EFFECT)
@@ -24,11 +24,10 @@ class SwitchToChattingTaskConfig : SingleTaskConfig {
behaviourConfigurationContext: BehaviourConfigurationContext
) = BehaviorBuilder.create {
it.group(
it.present(CobblemonMemories.DIALOGUES),
it.registered(MemoryModuleType.WALK_TARGET)
).apply(it) { _, walkTarget ->
it.present(CobblemonMemories.DIALOGUES)
).apply(it) { _ ->
Trigger { world, entity, _ ->
walkTarget.erase()
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET) // it may not even have this memory but clear it if it got it
entity.brain.setActiveActivityIfPossible(CobblemonActivities.NPC_CHATTING)
return@Trigger true
}
@@ -40,5 +40,7 @@ class SwitchToFightTaskConfig : SingleTaskConfig {
return@Trigger true
}
}
}.also {
behaviourConfigurationContext.addMemories(MemoryModuleType.ATTACK_TARGET)
}
}
@@ -23,6 +23,7 @@ class SwitchToHerdTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
behaviourConfigurationContext.addMemories(CobblemonMemories.HERD_LEADER)
return BehaviorBuilder.create {
it.group(
it.present(CobblemonMemories.HERD_LEADER)
@@ -8,16 +8,22 @@
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.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.SwitchToBattleTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class SwitchToNPCBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity> = SwitchToBattleTask.create()
): BehaviorControl<in LivingEntity> = SwitchToBattleTask.create().also {
behaviourConfigurationContext.addMemories(CobblemonMemories.NPC_BATTLING)
behaviourConfigurationContext.addSensors(CobblemonSensors.NPC_BATTLING)
}
}
@@ -18,6 +18,7 @@ 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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
import net.minecraft.world.entity.schedule.Activity
class SwitchToPanicWhenHostilesNearbyTaskConfig : SingleTaskConfig {
@@ -30,6 +31,8 @@ class SwitchToPanicWhenHostilesNearbyTaskConfig : SingleTaskConfig {
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
behaviourConfigurationContext.addMemories(MemoryModuleType.NEAREST_HOSTILE)
behaviourConfigurationContext.addSensors(SensorType.VILLAGER_HOSTILES)
return BehaviorBuilder.create {
it.group(it.present(MemoryModuleType.NEAREST_HOSTILE))
.apply(it) { nearestHostile ->
@@ -18,6 +18,7 @@ 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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
import net.minecraft.world.entity.schedule.Activity
class SwitchToPanicWhenHurtTaskConfig : SingleTaskConfig {
@@ -36,6 +37,8 @@ class SwitchToPanicWhenHurtTaskConfig : SingleTaskConfig {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return if (includePassiveDamage.resolveBoolean()) {
behaviourConfigurationContext.addMemories(MemoryModuleType.HURT_BY)
behaviourConfigurationContext.addSensors(SensorType.HURT_BY)
BehaviorBuilder.create {
it.group(it.present(MemoryModuleType.HURT_BY))
.apply(it) { _ ->
@@ -47,6 +50,8 @@ class SwitchToPanicWhenHurtTaskConfig : SingleTaskConfig {
}
}
} else {
behaviourConfigurationContext.addMemories(MemoryModuleType.HURT_BY_ENTITY)
behaviourConfigurationContext.addSensors(SensorType.HURT_BY)
BehaviorBuilder.create {
it.group(it.present(MemoryModuleType.HURT_BY_ENTITY))
.apply(it) { _ ->
@@ -8,6 +8,7 @@
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.npc.ai.SwitchToBattleTask
@@ -20,6 +21,7 @@ class SwitchToPokemonBattleTaskConfig : SingleTaskConfig {
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity> {
behaviourConfigurationContext.addMemories(CobblemonMemories.POKEMON_BATTLE)
return SwitchToBattleTask.createForPokemon()
}
}
@@ -36,6 +36,12 @@ class SwitchToSleepOnTrainerBedTaskConfig : SingleTaskConfig {
return null
}
behaviourConfigurationContext.addMemories(
CobblemonMemories.POKEMON_SLEEPING,
CobblemonMemories.POKEMON_BATTLE,
MemoryModuleType.WALK_TARGET
)
return BehaviorBuilder.create {
it.group(
it.absent(CobblemonMemories.POKEMON_BATTLE),
@@ -0,0 +1,74 @@
/*
* 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.bedrockk.molang.Expression
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
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.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* Directly sets the attack target of the entity to the nearest visible entity that matches the [entityCondition]
* and is within the [range].
*
* @author Hiroku
* @since June 23rd, 2025
*/
class TargetEntityTaskConfig : SingleTaskConfig {
val entityCondition: Expression = "true".asExpression()
val range: ExpressionOrEntityVariable = Either.left("24".asExpression())
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
behaviourConfigurationContext: BehaviourConfigurationContext
): BehaviorControl<in LivingEntity>? {
val range = range.resolveFloat()
behaviourConfigurationContext.addMemories(
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
MemoryModuleType.ATTACK_TARGET,
CobblemonMemories.ATTACK_TARGET_DATA
)
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
return BehaviorBuilder.create { instance ->
instance.group(
instance.present(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES),
instance.registered(MemoryModuleType.ATTACK_TARGET)
).apply(instance) { entities, attackTarget ->
Trigger { world, entity, _ ->
val target = instance.get(entities).findClosest {
runtime.withQueryValue("entity", it.asMostSpecificMoLangValue())
return@findClosest runtime.resolveBoolean(entityCondition)
}.orElse(null)
if (target != null && target.distanceTo(entity) <= range) {
val attackTargetData = CobblemonAttackTargetData(shouldContinue = entityCondition)
entity.brain.setMemory(CobblemonMemories.ATTACK_TARGET_DATA, attackTargetData)
attackTarget.set(target)
}
return@Trigger true
}
}
}
}
}
@@ -32,6 +32,8 @@ import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.sensing.SensorType
/**
* A configuration for a brain task. Its purpose is to generate a list of tasks to add to the brain of
@@ -57,6 +59,7 @@ interface TaskConfig {
cobblemonResource("do_nothing") to DoNothingTaskConfig::class.java,
cobblemonResource("get_angry_at_attacker") to GetAngryAtAttackerTaskConfig::class.java,
cobblemonResource("stop_being_angry_if_attacker_dead") to StopBeingAngryIfAttackerDeadTaskConfig::class.java,
cobblemonResource("stop_attacking_if_target_invalid") to StopAttackingIfTargetInvalidTaskConfig::class.java,
cobblemonResource("switch_npc_to_battle") to SwitchToNPCBattleTaskConfig::class.java,
cobblemonResource("look_at_battling_pokemon") to LookAtBattlingPokemonTaskConfig::class.java,
cobblemonResource("switch_npc_from_battle") to SwitchFromNPCBattleTaskConfig::class.java,
@@ -96,7 +99,8 @@ interface TaskConfig {
cobblemonResource("eat_grass") to EatGrassTaskConfig::class.java,
cobblemonResource("find_air") to FindAirTaskConfig::class.java,
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
cobblemonResource("battle_flight_task") to BattleFlightTaskConfig::class.java,
cobblemonResource("manage_flight_in_battle") to ManageFlightInBattleTaskConfig::class.java,
cobblemonResource("attack_hostile_mobs") to AttackHostileMobsTaskConfig::class.java,
cobblemonResource("move_into_fluid") to MoveIntoFluidTaskConfig::class.java,
cobblemonResource("find_herd_leader") to FindHerdLeaderTaskConfig::class.java,
cobblemonResource("follow_herd_leader") to FollowHerdLeaderTaskConfig::class.java,
@@ -104,8 +108,10 @@ interface TaskConfig {
cobblemonResource("switch_from_herd") to SwitchFromHerdTaskConfig::class.java,
cobblemonResource("maintain_herd_leader") to MaintainHerdLeaderTaskConfig::class.java,
cobblemonResource("count_followers") to CountFollowersTaskConfig::class.java,
cobblemonResource("hate_entity") to HateEntityTaskConfig::class.java,
cobblemonResource("target_entity") to TargetEntityTaskConfig::class.java,
)
val runtime = MoLangRuntime().setup()
}
@@ -8,6 +8,8 @@
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
@@ -22,6 +24,11 @@ class WakeUpTaskConfig : SingleTaskConfig {
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)
}
}
@@ -98,6 +98,12 @@ class WanderTaskConfig : SingleTaskConfig {
val wanderChanceExpression = wanderChance.asSimplifiedExpression(entity)
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
MemoryModuleType.LOOK_TARGET,
CobblemonMemories.PATH_COOLDOWN
)
return BehaviorBuilder.create {
it.group(
it.absent(MemoryModuleType.WALK_TARGET),
@@ -134,9 +140,6 @@ class WanderTaskConfig : SingleTaskConfig {
maximumHeight = maximumHeight,
world = world
)
// if (targetVec.y < minimumHeight || targetVec.y > maximumHeight) {
// return@Trigger false
// }
walkTarget.set(
CobblemonWalkTarget(
pos = pos,
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
@@ -50,11 +51,18 @@ class WaterWanderTaskConfig : SingleTaskConfig {
val wanderChanceExpression = wanderChance.asSimplifiedExpression(entity)
behaviourConfigurationContext.addMemories(
MemoryModuleType.WALK_TARGET,
MemoryModuleType.LOOK_TARGET,
CobblemonMemories.PATH_COOLDOWN
)
return BehaviorBuilder.create {
it.group(
it.absent(MemoryModuleType.WALK_TARGET),
it.registered(MemoryModuleType.LOOK_TARGET)
).apply(it) { walkTarget, lookTarget ->
it.registered(MemoryModuleType.LOOK_TARGET),
it.registered(CobblemonMemories.PATH_COOLDOWN)
).apply(it) { walkTarget, lookTarget, pathCooldown ->
Trigger { world, entity, time ->
if (entity !is PathfinderMob || !entity.isInWater) {
return@Trigger false
@@ -66,6 +74,8 @@ class WaterWanderTaskConfig : SingleTaskConfig {
return@Trigger false
}
pathCooldown.setWithExpiry(true, 60L)
val target = BehaviorUtils.getRandomSwimmablePos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt()) ?: return@Trigger false
walkTarget.set(
CobblemonWalkTarget(
@@ -83,7 +83,7 @@ interface ExperienceCandyUseEvent {
*
* @return If any experience was gained from the candy and if it was consumed.
*/
fun wasCandyConsumed() = this.experienceResult.experienceAdded > 0 && !player.isCreative
fun wasCandyConsumed() = this.experienceResult.experienceAdded > 0 && !player.hasInfiniteMaterials()
}
}
@@ -30,7 +30,7 @@ data class PokemonInteractionGUICreationEvent(
}
private fun getNextFreeOrientation(): Orientation {
var largest = Orientation.TOP_LEFT
var largest = Orientation.NORTH
for (orientation in Orientation.entries) {
if(!options.containsKey(orientation)) {
return orientation
@@ -42,4 +42,4 @@ data class PokemonInteractionGUICreationEvent(
}
return largest
}
}
}
@@ -29,20 +29,4 @@ interface EntityInteraction<T : Entity> {
* @return true if the interaction was successful and no further interactions should be processed
*/
fun onInteraction(player: ServerPlayer, entity: T, stack: ItemStack): Boolean
/**
* Decreases the stack size by a given amount.
* The stack size should be validated beforehand.
* If the [player] is in creative mode the decrement won't be performed.
*
* @param player The [ServerPlayer] that caused the interaction, this is used to check for creative mode.
* @param stack The [ItemStack] being mutated.
* @param amount The amount to deduct from the stack, default is 1.
*/
fun consumeItem(player: ServerPlayer, stack: ItemStack, amount: Int = 1) {
if (!player.isCreative) {
stack.shrink(amount)
}
}
}
@@ -112,7 +112,7 @@ class ShrinkItemEffect(val amount: Int = 1): InteractionEffect {
if (player.getItemInHand(InteractionHand.MAIN_HAND).isDamageableItem)
player.getItemInHand(InteractionHand.MAIN_HAND).hurtAndBreak(amount, player, EquipmentSlot.MAINHAND)
else
player.getItemInHand(InteractionHand.MAIN_HAND).shrink(amount)
player.getItemInHand(InteractionHand.MAIN_HAND).consume(amount, player)
}
companion object {
@@ -87,9 +87,7 @@ interface PokemonAndMoveSelectingItem {
player.sendSystemMessage(battleLang("bagitem.invalid").red())
} else {
battlePokemon.actor.forceChoose(BagItemActionResponse(bagItem, battlePokemon, move.template.name))
if (!player.isCreative) {
stack.shrink(1)
}
stack.consume(1, player)
}
}
@@ -98,7 +98,7 @@ interface PokemonSelectingItem {
} else {
battlePokemon.actor.forceChoose(BagItemActionResponse(bagItem, battlePokemon))
val stackName = BuiltInRegistries.ITEM.getKey(stack.item)
if (!player.isCreative) {
if (!player.hasInfiniteMaterials()) {
stack.shrink(1)
battlePokemon.actor.itemsUsed.add(bagItem)
}
@@ -108,6 +108,7 @@ import net.minecraft.tags.TagKey
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.damagesource.DamageTypes
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.EntityDimensions
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LightningBolt
import net.minecraft.world.entity.LivingEntity
@@ -296,6 +297,13 @@ object MoLangFunctions {
}
world.setBlock(BlockPos(x, y, z), block.defaultBlockState(), Block.UPDATE_ALL)
}
map.put("is_air") { params ->
val x = params.getDouble(0).toInt()
val y = params.getDouble(1).toInt()
val z = params.getDouble(2).toInt()
val blockState = world.getBlockState(BlockPos(x, y, z))
return@put DoubleValue(blockState.isAir)
}
map.put("get_block") { params ->
val x = params.getInt(0)
val y = params.getInt(1)
@@ -920,6 +928,34 @@ object MoLangFunctions {
return@put DoubleValue.ZERO
}
}
map.put("set_render_scale") { params ->
val scale = params.getDouble(0)
npc.renderScale = scale.toFloat()
return@put DoubleValue.ONE
}
map.put("render_scale") { _ -> DoubleValue(npc.renderScale) }
map.put("set_hitbox_scale") { params ->
val scale = params.getDouble(0).toFloat()
npc.hitboxScale = scale
npc.refreshDimensions()
return@put DoubleValue.ONE
}
map.put("hitbox_scale") { _ -> DoubleValue(npc.hitboxScale) }
map.put("set_hitbox") { params ->
if (params.params.size == 0) {
npc.hitbox = null
return@put DoubleValue.ONE
}
val width = params.getDouble(0).toFloat()
val height = params.getDouble(1).toFloat()
val eyeHeight = params.getDoubleOrNull(2)?.toFloat() ?: (height * 0.85F)
npc.hitbox = EntityDimensions.scalable(width, height).withEyeHeight(eyeHeight)
return@put DoubleValue.ONE
}
map.put("unset_hitbox") {
npc.hitbox = null
return@put DoubleValue.ONE
}
map.put("aspects") {
val aspects = npc.aspects
return@put aspects.asArrayValue { StringValue(it) }
@@ -1235,6 +1271,7 @@ object MoLangFunctions {
map.put("is_sprinting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("sprinting"))) }
map.put("in_air") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("in_air"))) }
map.put("is_wild") { DoubleValue(pokemonEntity.ownerUUID == null) }
map.put("is_in_party") { DoubleValue(pokemonEntity.pokemon.storeCoordinates.get()?.store is PartyStore) }
map.put("is_ridden") { DoubleValue(pokemonEntity.hasControllingPassenger()) }
map.put("has_aspect") { DoubleValue(it.getString(0) in pokemonEntity.aspects) }
map.put("is_pokemon") { DoubleValue.ONE }
@@ -1243,6 +1280,12 @@ object MoLangFunctions {
}) }
map.put("is_wearing_hat") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS)) }
map.put("is_wearing_face") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)) }
map.put("is_pastured") {
DoubleValue((pokemonEntity.tethering != null))
}
map.put("pasture_conflict_enabled") {
DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.PASTURE_CONFLICT))
}
map
}
)
@@ -39,9 +39,8 @@ class NPCClass {
var resourceIdentifier: ResourceLocation = cobblemonResource("dummy")
var names: MutableList<Component> = mutableListOf()
var aspects: MutableSet<String> = mutableSetOf() // These only make sense when applied via presets
var baseScale: Float = 1F
var hitbox = EntityDimensions.scalable(0.6F, 1.8F).withEyeHeight(1.62F)
var modelScale: Float = 0.9375F
var modelScale: Float = 0.9375F // Should this be removed in favour of the render scale stuff set on the entity?
var battleConfiguration = NPCBattleConfiguration()
var interaction: NPCInteractConfiguration? = null
var canDespawn = true
@@ -66,7 +65,6 @@ class NPCClass {
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeString(resourceIdentifier.toString())
buffer.writeCollection(names) { _, v -> buffer.writeText(v) }
buffer.writeFloat(baseScale)
buffer.writeFloat(hitbox.width)
buffer.writeFloat(hitbox.height)
buffer.writeBoolean(hitbox.fixed)
@@ -107,7 +105,6 @@ class NPCClass {
fun decode(buffer: RegistryFriendlyByteBuf) {
resourceIdentifier = ResourceLocation.parse(buffer.readString().toString())
names = buffer.readList { buffer.readText().copy() }.toMutableList()
baseScale = buffer.readFloat()
val length = buffer.readFloat()
val width = buffer.readFloat()
val fixed = buffer.readBoolean()

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