Compare commits

...
Author SHA1 Message Date
Guilherme Pereira 7dd92ca351 add expand and minimize assets to evolution tree 2026-06-11 07:02:27 -03:00
Guilherme Pereira 5359cc6c21 Merge branch 'main' into evolution-tree 2026-06-11 06:29:34 -03:00
Polymeta 26386638ad Merge branch 'PathingThresholds' into 'main'
Fixed wider pokemon being completely unable to hop up ledges

See merge request cable-mc/cobblemon!2304
2026-06-10 08:21:01 +00:00
JazzMcNade 5d1d99b64a Rolled back jump height change 2026-06-09 23:58:44 -05:00
Polymeta eb2a5837eb Merge branch 'oops-unsynced-tms' into 'main'
Sync TM Data

See merge request cable-mc/cobblemon!2303
2026-06-09 18:35:59 +00:00
Gertimoshka 93298d9a87 Sync TM Data 2026-06-09 20:48:35 +03:00
Polymeta 4d1f46c37c remove unused config values
Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-06-08 14:55:41 +01:00
Polymeta a2101b5759 whoops
Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-06-08 09:29:49 +01:00
Polymeta 187a190ec6 fix size categories not working properly on servers with non-default scales
Closes #2022

Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-06-08 09:16:57 +01:00
JazzMcNade 0d433ff394 Fixed wider pokemon being completely unable to hop up ledges
Fixed pokemon not being able to hop up snow
2026-06-07 23:26:31 -05:00
Polymeta d873399d05 Merge branch 'implement_pokemon' into 'main'
for merging when the last of the QA fixes are finished

See merge request cable-mc/cobblemon!2302
2026-06-05 08:28:27 +00:00
Jerzykv a7aab51e0d These didn't get in for some reason 2026-06-05 08:24:37 +02:00
ewwww e8e2057558 popplio t-pose fix 2026-06-04 23:51:06 -04:00
Polymeta 56b5dba911 Merge branch 'stoobid-aram' into 'main'
Stoobid Aram, Actually Fixed the Processor this time

See merge request cable-mc/cobblemon!2301
2026-06-04 22:51:01 +00:00
Aram f0a66458e5 Stoobid Aram, Actually Fixed the Processor this time 2026-06-05 00:31:55 +02:00
ewwww dba6a38f9e Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-06-04 13:07:42 -04:00
ewwww 342c0041e9 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUGH 2026-06-04 13:07:27 -04:00
Hiroku a811b3347c Merge branch 'implement_pokemon' into 'main'
Implement pokemon

See merge request cable-mc/cobblemon!2300
2026-06-04 10:53:32 +00:00
Polymeta 80e593f5c6 Merge branch 'fix-/locate-lie' into 'main'
Fixed the HeightRangeProcessor

See merge request cable-mc/cobblemon!2297
2026-06-04 10:43:12 +00:00
ewwww ff617348fe implemented arbok remodel 2026-06-04 06:00:31 -04:00
ewwww 1adecbf5f6 fixed incorrect "Head" naming for gallade 2026-06-04 04:37:32 -04:00
ewwww 29dbb13a0e cramorant poser tweaks 2026-06-04 04:11:06 -04:00
ewwww 67e03ecebd ditto poser tweaks 2026-06-04 04:10:57 -04:00
ewwww 215f48bdc7 musharna placeholder sleep 2026-06-04 04:03:05 -04:00
ewwww d4beab1bfb jynx poser tweaks 2026-06-04 04:02:56 -04:00
ewwww f2c21ec902 smoochum remodel 2026-06-04 04:02:46 -04:00
ewwww c9f3912677 updated omanyte and omastar's posers 2026-06-03 22:39:36 -04:00
ewwww c21b7d1a7d marked cherubi line as implemented + tweaked changelog 2026-06-03 19:59:45 -04:00
ewwww 26068694ad grafaiai animations 2026-06-03 07:15:38 -04:00
Polymeta c86d8f0696 Merge branch '1.8-move-effects-funny' into 'main'
1.8-move-effects-funny

See merge request cable-mc/cobblemon!2299
2026-06-03 09:55:40 +00:00
ewwww 16468059e4 oopsies forgot a few 2026-06-03 03:57:22 -04:00
ewwww 54dbe4769e changelog 2026-06-03 03:51:33 -04:00
321RetroGamer 82019c3722 1.8 MOVE STUFF (real)
NEW MOVES:
- Blizzard
- Disarming Voice
- Dragon Breath
- Dragon Rage
- Drain Punch
- Fairy Wind
- Fire Fang
- Gust
- Horn Drill (effect by Gesteeyy)
- Hydro Pump
- Ice Fang
- Leafage
- Leaf Storm
- Light Screen
- Night Shade
- Play Rough
- Reflect
- Rock Slide
- Sonic Boom
- Sucker Punch
- Supersonic
- Thunder Fang

ANIMATION .JSONS:
- Play Rough

TWEAKS:
- Confusion
- Eruption
- Flamethrower
- Hypnosis
- Poison Fang
- Protect
- Psychic
- Sing
- Spore
- String Shot
- Tail Whip
- Thunder Wave
- Water Pulse

FIXES:
- Dragon Claw (Action Effect Tweaks)
- Fire Punch (Action Effect Tweaks)
- Flame Burst (Delta Fixes)
- Flame Charge (Action Effect Tweaks)
- Frost Breath (Glow Fixes)
- Ice Punch (Action Effect Tweaks, Glow Fixes)
- Icy Wind (Action Effect Tweaks, Glow Fixes)
- Mud Sport (Glow Fixes)
- Quick Attack (Glow Fixes)
- Rage Powder (Action Effect Tweaks, Fixed Missing Texture Directory)
- Razor Leaf (Glow Fixes)
- Sand Attack (Action Effect Tweaks)
- Scratch (Glow Fixes)
- Shadow Claw (Action Effect Tweaks)
- Tackle (Glow Fixes)
- Thunder (Fixed Missing Texture Directory)
- Thunder Punch (Action Effect Tweaks)
- Water Gun (Glow Fixes)
- Water Sport (Glow Fixes)

MISCELLANEOUS:
- Shellder Line Anim/Poser Edits (Protect Signature Showcase)
2026-06-03 01:40:41 -05:00
ewwww 78f0951345 (proper) Ditto remodel 2026-06-03 00:27:04 -04:00
Paul 96aaab29e2 Changelog for lang 2026-06-03 11:55:47 +10:00
Paul b1def44953 Merge remote-tracking branch 'origin/implement_pokemon' 2026-06-03 11:55:30 +10:00
Paul e2e38add1d Merge remote-tracking branch 'origin/lang-updates' 2026-06-03 11:54:38 +10:00
ewwww 1db0b0709a animation tweaks 2026-06-02 05:41:51 -04:00
ewwww c3ce3db387 implemented Turtonator remodel 2026-06-02 05:41:38 -04:00
ewwww b5e6fd3816 e 2026-06-01 23:20:38 -04:00
MeAlam1 5b5dcddb25 Fixed the HeightRangeProcessor 2026-06-01 20:16:27 +02:00
ewwww 0158524bff oops. 2026-06-01 07:11:35 -04:00
ewwww 2611e311a7 luvdisc poser conversion + new animations 2026-06-01 06:47:42 -04:00
ewwww 17061691a1 corrected Feraligatr profile scale 2026-06-01 05:16:36 -04:00
ewwww 9c6d7ddfef implemented Tyranitar remodel 2026-06-01 05:16:23 -04:00
Polymeta e8119198c1 Merge branch 'type_alpha_drops' into 'main'
Alphas also drop items based on the pokemon types

See merge request cable-mc/cobblemon!2295
2026-05-31 08:58:53 +00:00
Hiroku 55c0e3e8a0 Merge branch 'IceTypeSnowImmunity' into 'main'
Added powdered snow immunity to ice types

Closes #1809

See merge request cable-mc/cobblemon!2293
2026-05-31 02:07:20 +00:00
PaulFreck 70443bc7b0 added optional tag for powdered snow immunity 2026-05-30 08:26:41 -05:00
Hiroku acb166b5b9 Merge branch 'implement_pokemon' into 'main'
Implement merge to main

See merge request cable-mc/cobblemon!2296
2026-05-30 06:17:46 +00:00
Carmendar 462c361998 No more eepy Seedot line in party/PC 2026-05-30 00:51:58 -05:00
Carmendar 76c90fb1ae Merge branch 'main' into implement_pokemon 2026-05-30 00:49:53 -05:00
Carmendar 27e11dee87 Gen3 alpha eyes 2026-05-30 00:40:24 -05:00
Paul d7c8b8dd62 Alphas also drop items based on the pokemon types 2026-05-30 14:15:00 +10:00
RedGenesectNinja eb12ccf6d0 Updated changelog 2026-05-29 18:52:22 -05:00
mystixmew e7b58edcd1 fix: resolve Linux compatibility issue in Getch class
msvcrt platform detection was broken - the try/except ImportError in
__init__ never triggered since the import attempt already happened at
module level. Replaced with a _has_msvcrt boolean flag set at import
time to correctly route Linux to _getch_unix. Also fixed _getch_unix
to return ch.encode() so key comparisons behave consistently across
platforms.
2026-05-28 17:43:18 -04:00
Polymeta ca5c2ba381 Merge branch 'shiny-volume-tweaks' into 'main'
Update sounds.json and changelog documentation

See merge request cable-mc/cobblemon!2294
2026-05-28 14:15:12 +00:00
SterrezoandPolymeta 8aa538d8e7 Update sounds.json and changelog documentation 2026-05-28 14:15:11 +00:00
Polymeta 1bd33a0635 Merge branch 'main' into implement_pokemon
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2026-05-28 15:13:23 +01:00
Polymeta ff9ca4ee09 Merge branch 'implementation-vibe-check' into 'main'
Added a script to automatically find implementation issues

See merge request cable-mc/cobblemon!2290
2026-05-28 14:10:57 +00:00
ewwww 1def8fcd1a oops 2026-05-28 06:14:50 -04:00
ewwww d53603ec49 futureproofing 2026-05-28 05:50:28 -04:00
Sterrezo 5362995fbb Added checks for wing flap sound keyframes 2026-05-27 14:23:26 +02:00
PaulFreck e2d0b12f94 small change to how freezing works 2026-05-26 20:01:58 -05:00
PaulFreck b32c2cb81c added powdered snow immunity to ice types 2026-05-26 19:48:29 -05:00
Sterrezo 98a7240191 Lenient spellcheck 2026-05-27 02:08:11 +02:00
Sterrezo 84adc0e1cb Minor oopsie 2026-05-27 01:55:55 +02:00
Sterrezo 3ab2dfa0b3 Anti-optimizations 2026-05-27 01:47:28 +02:00
Polymeta d67669a278 Merge branch 'smol-structure-crash-fix' into 'main'
Structure crash fix

See merge request cable-mc/cobblemon!2292
2026-05-26 22:12:37 +00:00
Sterrezo 2a85dee373 Fixed structure file names 2026-05-26 22:23:15 +02:00
Sterrezo 86e8238230 Grammar 2026-05-26 20:16:31 +02:00
Sterrezo bdc7b5a504 Small correction 2026-05-26 20:10:07 +02:00
Sterrezo f3c165d282 Added geo and detailed locator parity checks 2026-05-26 20:04:04 +02:00
Sterrezo 9caf8376bc Made this thing easier to use 2026-05-26 17:53:17 +02:00
Polymeta 8661f7a01e Merge branch 'z-fighting-b-gone' into 'main'
Pokedex Z-Fighting Begone

See merge request cable-mc/cobblemon!2289
2026-05-26 15:17:55 +00:00
Polymeta e933a03e92 Merge branch 'Habitat-Blocks-pt2' into 'main'
drifting icebergs, volcanic plumes, sketal falls, strange fungal dwellings,...

See merge request cable-mc/cobblemon!2291
2026-05-26 15:12:31 +00:00
Watuneni iteiteandWeblate 982fc054a9 Translated using Weblate (Japanese)
Currently translated at 98.5% (9183 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-26 07:06:18 +00:00
Watuneni iteiteandWeblate cb73bfb31b Translated using Weblate (Japanese)
Currently translated at 98.3% (9170 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-26 06:47:54 +00:00
Slippy 5b84c2c8a0 drifting icebergs, volcanic plumes, sketal falls, strange fungal dwellings, and lush cenotes have habitat blocks. Adjusted the rates of the nether habitats once again. 2026-05-25 12:28:04 -05:00
Sterrezo 9f998d92e6 Added a script to automatically find issues 2026-05-25 17:55:36 +02:00
Test b835bfe596 dex geo, deepslate texture 2026-05-25 03:10:46 -04:00
dhi_holo 757e3d48cb Update pokedex_red_model.json 2026-05-25 05:41:25 +10:00
dhi_holo 2fbf77dd65 Update pokedex_red_model.json 2026-05-25 05:22:41 +10:00
dhi_holo bd451bf951 Pokedex Z-Fighting Begone 2026-05-25 04:20:44 +10:00
geumuandWeblate d88a9dda92 Translated using Weblate (Korean)
Currently translated at 100.0% (9320 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-05-24 14:05:54 +00:00
Watuneni iteiteandWeblate 86c2282cf8 Translated using Weblate (Japanese)
Currently translated at 97.8% (9120 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-24 09:11:09 +00:00
Paul ac85cddeb6 Merge remote-tracking branch 'origin/main' 2026-05-24 14:41:27 +10:00
Paul a9c2373979 Fix moveset initialization on clients (it should use a dummy moveset) 2026-05-24 14:41:14 +10:00
Watuneni iteiteandWeblate 6ac8523cf5 Translated using Weblate (Japanese)
Currently translated at 97.2% (9060 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-23 17:05:17 +00:00
ManriqueandWeblate acb0aa854e Translated using Weblate (Spanish)
Currently translated at 99.8% (9310 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-23 17:05:16 +00:00
Polymeta d5cff3ba06 Merge branch 'Ghimmighoul' into 'main'
Made forcebattle identify pokemon

See merge request cable-mc/cobblemon!2288
2026-05-23 07:35:35 +00:00
Paul Freck 8e22538707 Made forcebattle identify pokemon 2026-05-23 01:51:16 -04:00
Hiroku f161699b6a Merge branch '1.8-qa-fixes-#4' into 'main'
Alpha pokemon level matching is more reliable when fishing and using pokesnacks

Closes #35

See merge request cable-mc/cobblemon!2287
2026-05-23 04:44:17 +00:00
ewwww fdafb1e64a updated en_us 2026-05-22 21:35:48 -04:00
Hiroku b0119e32c5 Merge branch 'Habitats-Blocks-pt1' into 'main'
Abandoned Fortress, Chorus Briar & Quartz Spikes habitats have habitat blocks

See merge request cable-mc/cobblemon!2286
2026-05-23 00:43:35 +00:00
Slippy 58bab4b94b Abandoned Fortress, Chorus Briar & Quartz Spikes habitats have habitat blocks 2026-05-22 12:29:30 -05:00
Polymeta a91bf60ff8 pokemon that get fished now get marked as "seen" in pokedex
Closes #2015

Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-05-22 18:05:49 +01:00
Polymeta 2d4c419216 remove unused override for chests
Closes #2016

Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-05-22 18:01:10 +01:00
plastered_crab 981f7307e6 Alpha pokemon level matching is more reliable when fishing and using pokesnacks 2026-05-22 08:54:01 -07:00
Polymeta c04345a789 Merge branch 'autocorrect' into 'main'
autocorrect

See merge request cable-mc/cobblemon!2284
2026-05-22 08:07:26 +00:00
Sterrezo 93e84e6ffd autocorrect 2026-05-22 09:17:24 +02:00
Polymeta cc6305bfec Merge branch 'qa-63' into 'main'
Fixed QA 63 for 1.8 / Ally-move turn skip

See merge request cable-mc/cobblemon!2283
2026-05-21 09:54:41 +00:00
CraterandPolymeta 7d38efaa50 Fixed QA 63 for 1.8 / Ally-move turn skip 2026-05-21 09:54:40 +00:00
Polymeta 9a3f5a605a Merge branch 'fix/particle-shader' into 'main'
Fix use the default minecraft shader instead of our own ( don't want to make...

See merge request cable-mc/cobblemon!2282
2026-05-21 09:51:30 +00:00
RedGenesectNinja bd525c8740 Implemented the rest of the Gen 4 alpha eyes 2026-05-21 04:30:28 -05:00
terrainwax b9922057ce Fix use the default minecraft shader instead of our own ( don't want to make the custom pipeline for Iris just for a 0.5 cutout XD ) 2026-05-21 10:58:11 +02:00
Polymeta d9c765ca53 Merge branch 'hydrapple-fix' into 'main'
Zero scaled locators don't get alpha eye effects, fixes hydrapple

See merge request cable-mc/cobblemon!2280
2026-05-21 08:39:49 +00:00
Polymeta 96c3f7764e Merge branch 'CloseSummary' into 'main'
Added ability to close summary and starter screen with summary button.

See merge request cable-mc/cobblemon!2274
2026-05-21 08:38:55 +00:00
Polymeta 255930751a Merge branch '1.8-qa-fixes-#3' into 'main'
Prevent Tera Blast from getting chosen when rolling for TM moves in general...

Closes #58

See merge request cable-mc/cobblemon!2278
2026-05-21 08:38:22 +00:00
Polymeta d3f32ee645 Merge branch 'mimic-block-json-list-additions' into 'main'
Mimic block json list additions

See merge request cable-mc/cobblemon!2281
2026-05-21 08:37:40 +00:00
Slippy e444206a55 and again 2026-05-21 02:51:30 -05:00
ewwww 209dee1d25 . 2026-05-21 03:48:37 -04:00
Slippy e58acd646f spelling & grammatical errors fixed 2026-05-21 02:45:25 -05:00
Slippy bdcc05aa78 added a bunch of blocks to the habitat block mimic list 2026-05-21 02:07:20 -05:00
Hiroku bb899118ef Merge branch '1.8-qa-fixes-#4' into 'main'
1.8 qa fixes #4

Closes #4

See merge request cable-mc/cobblemon!2279
2026-05-21 06:40:37 +00:00
Paul 71585174c0 Fixed an inconveniently small input max length for mimic block id 2026-05-21 16:39:44 +10:00
ewwww 1eedc4862a Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-05-21 00:17:40 -04:00
ewwww b1fbf9ca02 PYRO BALLING 2026-05-21 00:17:28 -04:00
Paul 3449c98b56 Zero scaled locators don't get alpha eye effects, fixes hydrapple 2026-05-21 13:53:20 +10:00
ewwww 5fda445274 cinderace tweak 2026-05-20 23:08:09 -04:00
plastered_crab 60aa991d55 Special moves are no longer searchable in the Search by Move Name function of the dex 2026-05-20 16:42:44 -07:00
plastered_crab 8da0fc34c6 Alphas drop rewards based on their level 2026-05-20 15:41:05 -07:00
plastered_crab 41c55d80a8 "Search By Drops" works for Seen Pokemon now too 2026-05-20 14:05:01 -07:00
plastered_crab 09dfbccb8e Legacy moves are no longer searchable in the Search by Move Name function of the dex 2026-05-20 13:53:19 -07:00
Jerzykv ce0265e954 Goodra animation tweaks 2026-05-20 22:38:56 +02:00
plastered_crab a66d263dd8 Add langs for Data Monitor Shiny and Alpha chance for Config 2026-05-20 12:33:06 -07:00
plastered_crab 5a929e3901 Prevent Tera Blast from getting chosen when rolling for TM moves in general (also for alphas getting the move) 2026-05-20 12:25:03 -07:00
ManriqueandWeblate da1654d9aa Translated using Weblate (Spanish)
Currently translated at 99.7% (9293 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-20 16:10:05 +00:00
ManriqueandWeblate 27132031cd Translated using Weblate (Spanish)
Currently translated at 99.6% (9292 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-20 16:09:24 +00:00
GenotypeXD cdc4a571b6 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-05-20 06:26:07 -05:00
GenotypeXD e8bc138e5d Gen 6 Alphas 2026-05-20 06:25:27 -05:00
ManriqueandWeblate 038d239f95 Translated using Weblate (Spanish)
Currently translated at 98.7% (9208 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-20 11:20:21 +00:00
Polymeta d95db24426 bump packsquash
Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-05-20 11:54:29 +01:00
Hiroku a64cbb7e8a Merge branch '1.8-more-qa-fixea' into 'main'
- Show SEEN pokemon in dex filters for Rideable and Learnable TM Moves

See merge request cable-mc/cobblemon!2277
2026-05-20 10:52:10 +00:00
Watuneni iteiteandWeblate 9b2a1dc065 Translated using Weblate (Japanese)
Currently translated at 96.9% (9035 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-20 10:26:50 +00:00
ManriqueandWeblate 3c222a3349 Translated using Weblate (Spanish)
Currently translated at 97.1% (9052 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-20 10:26:49 +00:00
Paul e2ba1dc575 Cleanup for pokedex GUI stuff 2026-05-20 20:01:56 +10:00
Polymeta f7e381924e Merge branch 'sneasler-ride-fix' into 'main'
Fixed basket sneasler causing crashes upon riding

See merge request cable-mc/cobblemon!2276
2026-05-20 09:43:30 +00:00
RedGenesectNinja a1035608c9 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-05-20 04:06:02 -05:00
RedGenesectNinja 2345565e38 Implemented more Gen 4 alpha eyes and a remodel for Chatot 2026-05-20 04:05:16 -05:00
plastered_crab f4c2a5197c why can't I create an MR 2026-05-20 01:41:33 -07:00
ewwww 620002c165 chopped off gastly's tongue & poked zubat's eyes out 2026-05-20 01:45:14 -04:00
Paul 361a8fcbe1 Fixed basket sneasler causing crashes upon riding 2026-05-20 13:18:05 +10:00
Polymeta e179e044ef Merge branch 'fix-cobblemon-boat-renderer' into 'main'
Fix cobblemon boat renderer

See merge request cable-mc/cobblemon!2275
2026-05-19 15:53:50 +00:00
Sterrezo d89224a684 FIxed incorrectly named sound events for Galarian Ponyta and Rapidash cries 2026-05-19 14:15:05 +02:00
Faintful f55d8737ba Add changelog 2026-05-18 19:57:00 +02:00
Faintful 336180656e Fix Cobblemon boat renderer registration for non-chest boats 2026-05-18 18:37:46 +02:00
ewwww 856eb2a1bd pyro balling 2026-05-18 06:33:20 -04:00
Paul Freck 620589681d Added ability to close summary and starter screen with summary button. 2026-05-18 05:44:12 -04:00
Polymeta 8359b1ade1 Merge branch 'complex-spawn-buckets' into 'main'
Rebuilt spawn buckets to be controlled by the spawner, allowing new buckets in specific contexts, and flattened habitat configuration classes

See merge request cable-mc/cobblemon!2267
2026-05-17 23:54:13 +00:00
TeggyandWeblate 136d7c08b8 Translated using Weblate (Spanish)
Currently translated at 94.2% (8786 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-17 16:28:35 +00:00
Jerzykv ddc03766bb Implemented alpha eyes/locators of Galar and Hisui 2026-05-17 17:08:25 +02:00
ewwww 81dccf9c07 various fixes 2026-05-17 08:05:04 -04:00
Watuneni iteiteandWeblate ea93b8c1d8 Translated using Weblate (Japanese)
Currently translated at 96.8% (9024 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-17 09:41:51 +00:00
Hiroku 8018c1142a Merge branch 'ability-capsule-returns-empty-bottle' into 'main'
Add conditional giveOrDropItemStack() call for returning empty bottles

See merge request cable-mc/cobblemon!2255
2026-05-17 06:56:27 +00:00
Hiroku cfca238573 Merge branch 'data-compatibility' into 'main'
Some Mod Compatibility

See merge request cable-mc/cobblemon!2269
2026-05-17 06:56:01 +00:00
Hiroku e3cf367e45 Merge branch 'riding-when-not-supposed-to-fix' into 'main'
Same fix for mounting a recalling a pokemon, but better

See merge request cable-mc/cobblemon!2268
2026-05-17 06:54:19 +00:00
Hiroku b9b01af451 Merge branch 'fix/fabric-publication-pom' into 'main'
Fix publication pom to include transitive dependencies now in JIJ

See merge request cable-mc/cobblemon!2271
2026-05-17 06:51:39 +00:00
Watuneni iteiteandWeblate 1abe39db3c Translated using Weblate (Japanese)
Currently translated at 96.6% (9012 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-17 02:13:26 +00:00
TeggyandWeblate 4e7cdb6266 Translated using Weblate (Spanish)
Currently translated at 94.2% (8786 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-17 02:13:25 +00:00
Carmendar 79b13acdc6 Gen7 alpha eyes 2026-05-16 20:43:04 -05:00
terrainwax c68f637b70 Fix publication pom to include transitive dependencies now in JIJ 2026-05-16 21:23:27 +02:00
Polymeta d44126179a Merge branch 'fix/neoforge-shader-init' into 'main'
Fix Neoforge shader initialization

See merge request cable-mc/cobblemon!2270
2026-05-16 17:37:47 +00:00
terrainwax 432b350d98 Fix Neoforge shader initialization 2026-05-16 18:45:48 +02:00
Faintful 26677420dd Add changelog 2026-05-16 11:55:48 +02:00
dhi_holo a1487e4ee5 Merge branch 'main' into data-compatibility 2026-05-16 19:46:53 +10:00
Sterrezo 78b2a7d721 Same fix for mounting a recalling a pokemon, but better 2026-05-16 11:42:34 +02:00
dhi_holo d4a3dfdb07 Phase 1 Complete
Added basic support for Create, Supplementaries/Supplementaries Squared/Amendments/Moonlight, Arts and Crafts, and Farmer's Delight (NeoForge and Fabric) in a variety of ways
2026-05-16 19:18:25 +10:00
Paul 0f3dcb760e Rebuilt spawn buckets to be controlled by the spawner, allowing new buckets in specific contexts, and flattened habitat configuration classes 2026-05-16 16:34:20 +10:00
ewwww 0ffd6fad90 gen 2 locators wip, pushing for now 2026-05-16 01:47:17 -04:00
geumuandWeblate 3c9661dfd3 Translated using Weblate (Korean)
Currently translated at 100.0% (9320 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-05-16 04:58:00 +00:00
Watuneni iteiteandWeblate 520f522f3c Translated using Weblate (Japanese)
Currently translated at 96.6% (9012 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-16 04:58:00 +00:00
TeggyandWeblate 113ae1f749 Translated using Weblate (Spanish)
Currently translated at 94.2% (8785 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-16 04:57:58 +00:00
ewwww 61bf5ffab1 feraligatr poser update 2026-05-15 23:40:09 -04:00
Hiroku 0e1b59fb25 Merge branch 'riding-when-not-supposed-to-fix' into 'main'
Prevent riding when Pokemon is being sent out or retrieved

See merge request cable-mc/cobblemon!2266
2026-05-16 01:09:42 +00:00
Sterrezo 3565015039 Remove the ability to send one self into the void and crash the game 2026-05-16 02:36:56 +02:00
Hiroku 218b90860b Merge branch 'implement_pokemon' into 'main'
implement_pokemon

See merge request cable-mc/cobblemon!2264
2026-05-15 23:03:46 +00:00
Polymeta a59573073f Merge branch 'sterr/sound' into 'main'
TMM and TM sound implementation + miscellaneous sound tweaks

See merge request cable-mc/cobblemon!2265
2026-05-15 21:52:17 +00:00
Sterrezo 6475d7d732 Fixed TM items playing unintended sounds 2026-05-15 23:38:37 +02:00
Sterrezo c467e98345 Update sounds.json 2026-05-15 21:04:47 +02:00
Sterrezo 6b206cfaaf TM Machine now stops playing sounds when broken 2026-05-15 20:57:13 +02:00
Sterrezo 8aac4c294f More TMM work and new TM sounds 2026-05-15 19:36:58 +02:00
Sterrezo 2e330076b8 Merge branch 'main' into sterr/sound 2026-05-15 18:20:57 +02:00
Jerzykv e1cd217290 Hisuian Zoroark fixes 2026-05-15 18:05:33 +02:00
Gustavo PuerariandWeblate 87da3e83a0 Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.5% (9090 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2026-05-15 14:36:53 +00:00
geumuandWeblate c325d0215a Translated using Weblate (Korean)
Currently translated at 99.6% (9290 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-05-15 14:36:50 +00:00
TeggyandWeblate 8afb4e6d16 Translated using Weblate (Spanish)
Currently translated at 93.7% (8742 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-15 14:36:47 +00:00
dhi_holo 60f00ca34d Merge branch 'main' into data-compatibility 2026-05-16 00:10:15 +10:00
dhi_holo 416a2ac390 Create Farmer's Split
Added first pass of inbuilt support for Create, and split Farmer's Delight compat between two jsons for proper compatibility on the two loaders
2026-05-16 00:08:36 +10:00
ManriqueandWeblate 0ffff6f4af Translated using Weblate (Spanish)
Currently translated at 93.7% (8736 of 9320 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-05-15 13:06:40 +00:00
Polymeta 690ada8271 Merge branch 'my-goodness-more-fixes' into 'main'
There are more damn 1.8 QA fixes

See merge request cable-mc/cobblemon!2256
2026-05-15 08:27:44 +00:00
Polymeta b1b06f19b2 Merge branch 'click-to-cry' into 'main'
Play Pokemon cries from summary screen

See merge request cable-mc/cobblemon!2252
2026-05-15 08:25:30 +00:00
dhi_holo 5bc41245ad Merge branch 'main' into data-compatibility 2026-05-15 15:49:52 +10:00
Paul 490fa91ce7 Removed fossil structure tag as we don't use structures for fossil stuff anymore 2026-05-15 14:18:17 +10:00
Gertimoshka 8606d6928d Changes and Changelog 2026-05-15 07:08:09 +03:00
Hiroku 5897b43564 Merge branch 'sounds-unlaggifier' into 'main'
Fix specific quirk of CancelableSoundInstance causing lagspike when far away from a loaded block that creates it

See merge request cable-mc/cobblemon!2248
2026-05-15 03:47:48 +00:00
Gertimoshka 9fd8d32215 Changelog 2026-05-15 06:46:34 +03:00
dhi_holo 03c278229b Merge branch 'main' into data-compatibility 2026-05-15 13:34:54 +10:00
dhi_holo 8ce3322105 New Screen Who This 2026-05-15 13:34:40 +10:00
Paul 364d084584 Small miscellaneous touchups including from thetechgo's MR 2026-05-15 13:01:26 +10:00
Paul 916e6de1d2 Fixed client's "sound" function not taking a volume property as the second argument but requiring one to specify pitch (whack) 2026-05-15 12:03:21 +10:00
ewwww 0b9e706a36 NIDO NIDO BEAMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM 2026-05-14 21:57:38 -04:00
Paul 6d4f529fc0 Some lang updates in changelog 2026-05-15 11:54:50 +10:00
Paul 015de548d3 Merge remote-tracking branch 'origin/main' 2026-05-15 11:53:11 +10:00
Paul 04ca03b3a5 Merge remote-tracking branch 'origin/lang-updates' 2026-05-15 11:53:01 +10:00
Hiroku c7c145ab78 Merge branch 'scrolling-texture-emissive-fix' into 'main'
Fixed scrolling texture layer not working with emissive.

See merge request cable-mc/cobblemon!2260
2026-05-15 01:48:31 +00:00
JadedArts a376863953 One last tweak to Draco Meteor's visuals 2026-05-14 12:28:32 -05:00
Sterrezo 2e68c3fc44 Lowered the volume of Zebstrika's cry 2026-05-14 16:53:49 +02:00
Sterrezo 36f2eee7f9 Oh right, the sounds.json 2026-05-14 16:52:33 +02:00
Sterrezo 71ac29ba8b Merge branch 'implement_pokemon' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon 2026-05-14 16:48:55 +02:00
Sterrezo 781c82230e I want to get off Draco Meteor's wild ride 2026-05-14 16:48:33 +02:00
Jerzykv c58d49ebab fixed hisuian samurott exploding the game 2026-05-14 16:39:49 +02:00
dhi_holo fd8d5630f4 Ya Like Compatibility? 2026-05-14 21:28:28 +10:00
Jerzykv a86b11fdd5 implemented alpha eyes/locators of Paldea 2026-05-14 13:12:09 +02:00
Jerzykv 829dca9d99 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-05-14 12:43:04 +02:00
Jerzykv 0f0368f3bd Maushold fixes 2026-05-14 12:42:49 +02:00
ewwww 6533030d36 oh brother 2026-05-14 06:21:38 -04:00
ewwww 0efb0d9767 remaining gen 1 eye locators 2026-05-14 06:15:17 -04:00
Paul 8151f9b3e6 Handle the scraping of multipliers more dynamically too, using the Dictionary tab 2026-05-14 20:11:24 +10:00
RedGenesectNinja 4e8ffd3558 Fixed Bidoof's cry not playing a sound 2026-05-14 03:31:41 -05:00
Paul b88873fbc3 Slight upgrade to herds that they support leader-only entries, added scraper for herd data, deleted example herd 2026-05-14 18:10:17 +10:00
RedGenesectNinja dba1ab26a5 I forgot to implement Bidoof's new animations 2026-05-14 02:53:22 -05:00
ewwww cc2295d629 updated models with locators for maushold, added alpha eyes for veluza and dondozo 2026-05-14 03:26:48 -04:00
ewwww 4d3d8d1607 updated models with (eye) locators for:
poliwag, poliwhirl, poliwrath, machop, machoke, machamp, bellsprout, weepinbell, victreebel, tentacool, geodude, graveler, golem, ponyta, rapidash, slowpoke, slowbro, farfetch'd, doduo, dodrio, seel, grimer, muk, shellder, cloyster, gastly, haunter, onix, krabby, kingler, voltorb, electrode, and exeggutor
2026-05-14 03:26:20 -04:00
RedGenesectNinja 1d09360844 Implemented some Gen 4 alpha eyes and remodels for Bidoof and Cranidos 2026-05-14 01:03:46 -05:00
Polymeta 079e75d828 Merge branch 'alpha-moveset-fix' into 'main'
Fixed alpha pokemon not using full movesets

See merge request cable-mc/cobblemon!2263
2026-05-13 10:10:51 +00:00
Paul a3567ead04 Merge remote-tracking branch 'origin/main' into alpha-moveset-fix 2026-05-13 18:18:24 +10:00
Paul f4fef2855b Fixed alpha pokemon not using full movesets 2026-05-13 18:18:13 +10:00
Hiroku 6f614eb02e Merge branch 'implement_pokemon' into 'main'
Implement pokemon

See merge request cable-mc/cobblemon!2232
2026-05-13 08:11:53 +00:00
Paul 72b82858b3 Merge remote-tracking branch 'origin/main' into Habitat-Block-Implementation 2026-05-13 17:16:45 +10:00
Hiroku 361047c309 Merge branch 'Habitat-Block-Implementation' into 'main'
Habitat block implementation

See merge request cable-mc/cobblemon!2261
2026-05-13 06:58:56 +00:00
Paul 18f43f72ad Fixed multiplayer joins failing due to interactions with no cooldown field not loading defaults properly 2026-05-13 16:46:48 +10:00
Paul cbb409b057 Translatable lang for all the habitat editor fields 2026-05-13 16:07:18 +10:00
Paul f8cec09f70 Resolve some conflicts with habitat JSONs and made lang keys for all the to-be-implemented ones 2026-05-13 15:33:44 +10:00
Paul 5579975b46 Merge remote-tracking branch 'origin/main' into Habitat-Block-Implementation
# Conflicts:
#	common/src/main/resources/data/cobblemon/habitat_pools/abandoned_fortress.json
#	common/src/main/resources/data/cobblemon/habitat_pools/chorus_briar.json
#	common/src/main/resources/data/cobblemon/habitat_pools/crimson_fungal_dwelling.json
#	common/src/main/resources/data/cobblemon/habitat_pools/drifting_icebergs.json
#	common/src/main/resources/data/cobblemon/habitat_pools/quartz_spikes.json
#	common/src/main/resources/data/cobblemon/habitat_pools/skeletal_fall.json
#	common/src/main/resources/data/cobblemon/habitat_pools/strange_fungal_dwelling.json
#	common/src/main/resources/data/cobblemon/habitat_pools/volcanic_plume.json
#	common/src/main/resources/data/cobblemon/habitat_pools/warped_fungal_dwelling.json
2026-05-13 14:53:29 +10:00
CaptainLennie 5a57f41fbb Fixed snivy's back problems 2026-05-12 15:52:00 +02:00
CaptainLennie 1845faf9ad Updated samurott textures 2026-05-12 15:48:54 +02:00
Polymeta 0e93682457 Merge branch 'updated-spawns-and-drops' into 'main'
Scrapes for spawns and drops and habitat pools

See merge request cable-mc/cobblemon!2262
2026-05-12 09:06:32 +00:00
ewwww cef69f478d fixed alpha eyes for rattata, raticate, raichu, sandshrew, & sandslash
added locators for nidoran♀, nidorina, nidoqueen, nidoran♂ , nidorino, vulpix (both forms), ninetales (both forms), jigglypuff, wigglytuff, oddish, gloom, vileplume, paras, parasect, venonat, venomoth, diglett (both forms), dugtrio (both forms), meowth (all forms), persian (both forms), psyduck, golduck, mankey, primeape, and growlithe
2026-05-12 04:55:45 -04:00
Paul 5ea7bc9c48 Updated spawn scraper to do habitats too and fixed some drop scrapes 2026-05-12 18:15:22 +10:00
Paul bfc8ace83a Updated spawn scraper to use google doc and rescraped spawns and drops 2026-05-12 16:13:55 +10:00
Paul e0f93fd797 Added herdLevelRange property in herds to do what the levelRange used to, levelRange is now a clamping around un-offset spawn level 2026-05-12 16:13:40 +10:00
Slippy ba13414ada Changed the biome tags of quartz spikes and strange fungal dwellings 2026-05-12 00:36:02 -05:00
Slippy 66c63d54db added end stone to habitat block mimic list 2026-05-12 00:29:19 -05:00
Slippy 9e836bcc3b added habitat blocks to drifting icebergs habitat 2026-05-12 00:23:04 -05:00
Slippy 27fb1f6c66 Implementing Placeholder Habitat Block Jsons 2026-05-11 19:08:40 -05:00
Tyzillion 7f60885f92 I dum dum and did not account for breeze wind render type not allowing emissive. Made it so that if the layer has emissive enabled it uses the energy swirl render type instead. 2026-05-11 18:48:07 -04:00
Sterrezo cb7f6d7bba Updated TM Machine sounds (again), separated the starting sound with a loop 2026-05-11 20:15:54 +02:00
Polymeta a3498fe03b Merge branch 'small-fix' into 'main'
Remove Unused ClientDataSynchronizer

See merge request cable-mc/cobblemon!2240
2026-05-11 14:46:26 +00:00
Polymeta af4af3395c Merge branch 'two-sorting-tweaks' into 'main'
Two Sorting Tweaks

See merge request cable-mc/cobblemon!2259
2026-05-11 14:29:57 +00:00
ewwww 3ab07ecbca added cries to sandshrew + proper alpha eyes for sandslash 2026-05-11 05:26:17 -04:00
dhi_holo b96eccbf2f Changed Regional Delicacy sorting to match dex order 2026-05-11 18:08:46 +10:00
dhi_holo afa7426116 Update CobblemonItemGroups.kt
Fixed Type Gem Block order
2026-05-11 16:15:13 +10:00
ewwww a5ace52cb5 typo 2026-05-10 22:43:32 -04:00
Sterrezo 9f3940bb31 Volume rebalancing 2026-05-10 22:55:35 +02:00
ewwww 8a8c131a44 Primarina size fix 2026-05-10 16:39:59 -04:00
ewwww 8b0fba4201 SANDSHREW REMODEL (and locators) 2026-05-10 06:56:25 -04:00
Hiroku e1e04b19bf Merge branch 'fix-collecting-honey-from-saccharine-leaf-block-with-full-inventory' into 'main'
Refactor addItem() call to giveOrDropItemStack()

Closes #2009

See merge request cable-mc/cobblemon!2253
2026-05-10 10:23:19 +00:00
Hiroku a04beb1ce8 Merge branch 'fix-remove-mulch-from-berry-tree' into 'main'
Fix remove mulch from berry tree

Closes #2011

See merge request cable-mc/cobblemon!2258
2026-05-10 10:22:41 +00:00
ewwww bd9aea7c59 pikachu + raichu updated locators 2026-05-10 05:01:12 -04:00
Sterrezo 757e3a7ff7 Burn sound now stops when crafting TMs is done 2026-05-10 10:37:19 +02:00
Paul 66d03651f9 Added q.failed to move instruction action effects 2026-05-10 13:23:10 +10:00
Faintful 3c1577d58f Add changelog 2026-05-10 02:06:45 +02:00
Faintful dd7d562228 Add changelog 2026-05-10 01:56:52 +02:00
Faintful a01ac32e54 Fix setMulch() not being called in useWithoutItem() 2026-05-10 01:38:43 +02:00
Sterrezo 5c0ae854bf Fixed TM inserting sound playing twice, more volume tweaks 2026-05-09 19:22:02 +02:00
Sterrezo 55c189b749 TM Craft now plays from the block + volume tweaks to the TM Machine 2026-05-09 19:11:49 +02:00
Gertimoshka b5b81fa1aa Implemented the TMM sounds 2026-05-09 19:19:54 +03:00
Sterrezo eda58859ce Fix empty tm machine sounds 2026-05-09 17:33:58 +02:00
Sterrezo 3888a48cb0 Tweaks to block sound positions and the /pc command 2026-05-09 16:20:52 +02:00
ewwww c9b609a3f8 rattata + raticate locators (idgaf if raticate looks a little wonky for now IT'S GETTING REMODELED ANYWAY) 2026-05-09 06:55:57 -04:00
Sterrezo 70fb7c87ad Wip implementation of TMM sounds 2026-05-09 12:45:48 +02:00
Sterrezo a24189b816 Volume tweaks to display cases and evolution stone blocks 2026-05-09 12:05:42 +02:00
Gertimoshka c0d80634a4 Regional Food are now attempted to be consumed first, before applying use on, shifting will skip the consuming 2026-05-08 13:37:52 +03:00
Gertimoshka b52e4de85c Pokerod Bobber will promtly self destruct if the bait of used rod is changed 2026-05-08 13:26:21 +03:00
Gertimoshka 7d37a98a58 Aprijuice will be usable on pokemon with Max Ride stats if they decrease stat, as well as checking for stat to not decrease below allowed 2026-05-08 11:27:45 +03:00
Hiroku a424796aa8 Merge branch 'fix/particle-material-batching' into 'main'
Fix particle culling and shader wiring for per-material batching

See merge request cable-mc/cobblemon!2254
2026-05-08 06:12:28 +00:00
Faintful 8518be0d44 Add conditional giveOrDropItemStack() call for returning empty bottles 2026-05-07 20:35:41 +02:00
terrainwax 24760270bd Fix particle culling and shader wiring for per-material batching 2026-05-07 20:13:36 +02:00
Faintful 19f9490274 Refactor addItem() call to giveOrDropItemStack() 2026-05-07 18:56:02 +02:00
ewwww 93a94f04a1 a portion of the gen 1 locator fixes
bulbasaur, ivysaur, venusaur, charmander, charmeleon, charizard, squirtle, wartortle, blastoise, caterpie, metapod, butterfree, weedle, kakuna, beedrill, pidgey, pidgeotto, pidgeot, spearow, fearow, & ekans
2026-05-07 05:44:20 -04:00
CaptainLennie 97eac48cd7 Alpha locator'd emolga and updated its model 2026-05-06 22:39:01 +02:00
CaptainLennie 2c31f002b2 Unova alpha fixes part 5 2026-05-06 22:16:33 +02:00
Polymeta 4f0eb16ab0 Merge branch 'interact-wheel-qol' into 'main'
Pressing the inventory key now closes the interact wheel gui

See merge request cable-mc/cobblemon!2247
2026-05-06 06:20:00 +00:00
Polymeta 5004b61967 Merge branch 'Structure-Fixes-Part-4' into 'main'
Structure fixes part 4

See merge request cable-mc/cobblemon!2251
2026-05-06 06:16:34 +00:00
MyslippyandPolymeta cf137efa02 Structure fixes part 4 2026-05-06 06:16:34 +00:00
Breezyasha 862c0bda89 update changelog 2026-05-06 00:17:19 -04:00
Gertimoshka 868874b06d Stop some sounds from causing lag from constantl being created properly, then being removed on the same tick later 2026-05-05 13:53:23 +03:00
Sterrezo 068e4a1c92 Pressing the inventory key now closes the interact wheel gui 2026-05-05 08:55:26 +02:00
Breezyasha 267f2aa5a8 Merge branch cobblemon:main into click-to-cry 2026-05-05 03:31:40 +00:00
Polymeta 333d8fa732 Merge branch 'sterr/sound' into 'main'
Couple of sound tweaks

See merge request cable-mc/cobblemon!2245
2026-05-04 19:43:06 +00:00
Sterrezo e8d4e406d5 Update CHANGELOG.md 2026-05-04 18:39:53 +02:00
Sterrezo 9e5c296309 More sound tweaks and fixes to type gems 2026-05-04 18:38:46 +02:00
Sterrezo 69dc89b04f Replaced the apricorn harvesting sound with a new placeholder 2026-05-04 18:14:35 +02:00
Sterrezo dd31fb1a51 Lowered the volume of berry harvesting sound 2026-05-04 17:54:39 +02:00
Sterrezo 9b3a729b3c Type gem block and cluster sound update 2026-05-04 17:53:46 +02:00
CaptainLennie c72ab20cfa Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-05-03 22:26:42 +02:00
CaptainLennie 3cfc915b1a Unova alpha fixes part 4 2026-05-03 22:15:35 +02:00
Jerzykv b8541486d4 Implemented Smoliv line remodels 2026-05-03 21:16:42 +02:00
Jerzykv c69b38454e Fixed tiny error in Talonflame's animations 2026-05-03 20:59:11 +02:00
CaptainLennie 0e5787b8ab Unova alpha fixes part 3 2026-05-03 20:54:17 +02:00
plastered_crab 082be6f2d0 - Show SEEN pokemon in dex filters for Rideable and Learnable TM Moves
- Fix Rideable dex filter to show all rideable pokemon if SEEN or OWNED
2026-05-03 11:49:25 -07:00
plastered_crab 398f14efd5 Reveal drops and move info on Seen / Scanned Pokemon too 2026-05-03 11:15:43 -07:00
CaptainLennie e8ace8ba05 Unova alpha fixes part 2 2026-05-03 13:05:35 +02:00
CaptainLennie 1a78625111 Unova Model & locator fixes part 1 2026-05-03 11:55:24 +02:00
CaptainLennie 596c2b95b4 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-05-03 11:07:19 +02:00
CaptainLennie 38648111a6 Updated torchic locators 2026-05-03 11:07:08 +02:00
JadedArts 149b8f27e6 Draco Meteor is no longer backwards 2026-05-02 18:35:14 -05:00
ewwww 91433d7e13 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-05-02 15:49:06 -04:00
ewwww 85aadbabe9 i need 2 leave this somewhere , raichu alpha eyes texture 2026-05-02 15:48:44 -04:00
RedGenesectNinja e64c1487cf Restored Ninjask's ability to do barrel rolls 2026-05-02 00:58:49 -05:00
JadedArts 4d866f6207 More Draco Meteor Fixes
Tweaked ring color gradient
Made crater rocks affected by environment lighting
Fixed meteors playing even on miss
2026-05-01 12:21:56 -05:00
MeAlam1 e81418836e Remove Unused ClientDataSynchronizer 2026-05-01 17:44:57 +02:00
CaptainLennie 3d779e637b Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-05-01 00:59:52 +02:00
CaptainLennie bd0ad89971 Implemented shedinja, skwovet & greedent animations 2026-05-01 00:59:37 +02:00
Polymeta 586ced7bfb Merge branch 'main' into 'implement_pokemon'
# Conflicts:
#   common/src/main/resources/data/cobblemon/recipe/metal_alloy.json
2026-04-30 22:43:58 +00:00
Sterrezo 218f2c67d3 The real draco meteor was friends we made along the way (more sound tweaks) 2026-04-30 20:14:11 +02:00
Breezyasha 59b0397ea4 Merge branch cobblemon:main into click-to-cry 2026-04-30 04:22:08 +00:00
Breezyasha aadb78149c changelog 2026-04-30 00:19:51 -04:00
CaptainLennie 3305874dd4 Implemented sewaddle & swadloon animations 2026-04-30 00:31:32 +02:00
CaptainLennie 2f688291dc Implemented leavanny animations 2026-04-29 23:20:50 +02:00
CaptainLennie 1f099b231c Fixed talonflame line walk speeds & flygon flight sounds 2026-04-29 21:48:35 +02:00
JadedArts c1ccc718cc Fixes to particles
Renamed explosion_floorscorch.png and explosion_floorscorch_big.png to floorscorch.png and floorscorch_big.png and moved to the generic folder under a new folder "scorch" and updated Explosion and Draco Meteor particles accordingly.

Fixed issue in flamethrower_actor that caused drag to be able to be infinite.
2026-04-29 12:22:40 -05:00
Jade 74df81006b Slightly reduced delay at the start of Draco Meteor 2026-04-29 15:23:27 +00:00
Sterrezo e7a87e299c First draft of draco meteor sound implementation 2026-04-29 14:25:56 +02:00
ewwww c688e9f80c Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-04-28 23:02:47 -04:00
ewwww ac1897b41a updated stat increase/decrease particles and added alpha boost particles 2026-04-28 23:02:01 -04:00
ewwww 40e8f4efa5 added eye locators to Nidoking's model 2026-04-28 23:01:34 -04:00
ewwww e00165aafb added animation for Draco Meteor 2026-04-28 23:01:14 -04:00
Breezyasha b2015c9cd8 Play pokemon cry in summary screen 2026-04-28 21:26:08 -04:00
GenotypeXD d0b796f777 Changelog Fixes 2026-04-28 19:07:25 -05:00
GenotypeXD 83488ec728 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon
# Conflicts:
#	common/src/main/resources/assets/cobblemon/textures/pokemon/0124_jynx/jynx_alpha.png
#	common/src/main/resources/assets/cobblemon/textures/pokemon/0729_brionne/brionne_alpha.png
2026-04-28 19:02:01 -05:00
GenotypeXD b3d387d8da Implemented Jynx Remodel, Popplio line Remodel, and Fletchling line animations 2026-04-28 19:00:42 -05:00
CaptainLennie 902c6751c5 Added milotic ride animations 2026-04-28 15:22:22 +02:00
CaptainLennie 4088f144e4 Fixed mantine's ride sounds 2026-04-28 13:57:09 +02:00
CaptainLennie 3e592b21f1 Fixed honchkrow's ride sounds & added new wing flap sounds 2026-04-28 13:48:08 +02:00
CaptainLennie b1186c8033 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-04-28 13:21:52 +02:00
CaptainLennie d038f63024 Fixed crobat's ride sounds & added new wing flap sounds 2026-04-28 13:21:26 +02:00
Sterrezo 7a3088eb59 Unbroke everything and fixed Alolan Sandslash as well 2026-04-28 12:30:43 +02:00
CaptainLennie de51d2b1b2 Updated drampa's poser 2026-04-28 12:25:49 +02:00
CaptainLennie 3c3aa3d4a3 Updated aerodactyl locators & changelog 2026-04-28 12:19:51 +02:00
Sterrezo 50e4829b79 Fixed Sandslash's missing cry crashing the game 2026-04-28 12:17:46 +02:00
ewwww ebdd06a4a9 added hisui bias bergmite model 2026-04-28 05:56:02 -04:00
ewwww 82fd4bae08 goomy, dartrix, and rowlet hisui bias updates 2026-04-28 05:17:58 -04:00
ewwww 277a7dc32b added mime jr galar bias 2026-04-28 04:36:57 -04:00
ewwww f00d578f64 updated dewott hisui bias 2026-04-28 04:36:40 -04:00
ewwww ea9fba72ec added metal alloy recipe 2026-04-28 04:36:23 -04:00
ewwww 4654c3c2b8 updated oshawott hisui bias 2026-04-28 04:36:12 -04:00
ewwww b4496b30a9 updated petilil hisui bias 2026-04-28 04:36:01 -04:00
ewwww 431662b237 updated exeggcute alola bias 2026-04-28 04:35:42 -04:00
ewwww 1299214d61 updated koffing galar bias 2026-04-28 04:35:26 -04:00
ewwww c5c2c3a059 updated quilava hisui bias 2026-04-28 04:35:05 -04:00
ewwww 64b7970cb5 updated cyndaquil hisui bias 2026-04-28 04:34:51 -04:00
ewwww ce6c777c4e updated cubone alola bias 2026-04-28 04:34:19 -04:00
ewwww 284b032dd8 updated pichu alola bias 2026-04-28 04:33:42 -04:00
ewwww 23d70ab1fe updated pikachu alola bias 2026-04-28 04:33:07 -04:00
ewwww 3340239440 took garchomp to therapy so it no longer sleep t-poses 2026-04-27 22:27:29 -04:00
ewwww e513d52c3d fixed nidoking's walk speed 2026-04-27 21:59:26 -04:00
ewwww edd4d18150 corrected hydrapple's german name 2026-04-25 03:30:41 -04:00
Watuneni iteiteandWeblate a1b6bd79d2 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-04-11 21:33:38 +00:00
Watuneni iteiteandWeblate 83eb483f0b Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-03-26 06:45:59 +00:00
Watuneni iteiteandWeblate d8498d7a37 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-03-25 11:05:22 +00:00
Watuneni iteiteandWeblate 3693e7eec0 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-03-25 05:21:29 +00:00
Watuneni iteiteandWeblate 60c9f5d054 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-03-24 20:51:43 +00:00
washashu0905andWeblate e1541a3512 Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 98.2% (8898 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2026-03-22 01:23:31 +00:00
washashu0905andWeblate 1c1c3f51bb Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 97.0% (8792 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hant/
2026-03-20 20:39:49 +00:00
阿鱼andWeblate 500f1f53a4 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-03-15 22:11:24 +00:00
Watuneni iteiteandWeblate 9ed10bb217 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-03-15 03:33:00 +00:00
Watuneni iteiteandWeblate 2f6d4313e7 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-03-13 18:46:43 +00:00
阿鱼andWeblate d640a04fa6 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-03-10 18:05:39 +00:00
geumuandWeblate 7749f346b5 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-03-06 16:37:11 +00:00
wajosalo21xandWeblate a29bc68663 Translated using Weblate (Spanish (Ecuador))
Currently translated at 98.3% (8908 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es_EC/
2026-03-03 21:07:51 +00:00
阿鱼andWeblate 1358380905 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-03-03 21:07:51 +00:00
wajosalo21xandWeblate 2679885fb4 Translated using Weblate (Spanish (Ecuador))
Currently translated at 98.3% (8908 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es_EC/
2026-02-28 19:45:51 +00:00
阿鱼andWeblate 278c5d8e81 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-02-28 19:45:50 +00:00
Weblate a55916998b Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/
2026-02-27 02:46:24 +00:00
Patch Notes GuyandWeblate cca2d54682 Translated using Weblate (Spanish (Ecuador))
Currently translated at 0.0% (0 of 0 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es_EC/
2026-02-27 02:44:12 +00:00
Weblate f5bd6a4054 Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/
2026-02-27 02:40:18 +00:00
Patch Notes GuyandWeblate 13466815e5 Added translation using Weblate (Spanish (Ecuador)) 2026-02-27 02:40:15 +00:00
Watuneni iteiteandWeblate e871047cf1 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-02-25 21:37:45 +00:00
Guilherme Pereira 4421303d3b Merge branch 'main' into evolution-tree 2026-02-24 21:03:56 -03:00
Nico MerenqandWeblate a1de8c95f6 Translated using Weblate (Russian)
Currently translated at 79.5% (7206 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ru/
2026-02-24 17:47:11 +00:00
geumuandWeblate eb94bdb9c2 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-02-21 11:40:10 +00:00
arvid6andWeblate 509c2365bb Translated using Weblate (Spanish)
Currently translated at 94.0% (8522 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-20 23:12:50 +00:00
arvid6andWeblate 6271476ed3 Translated using Weblate (Spanish)
Currently translated at 93.2% (8445 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-20 10:57:20 +00:00
arvid6andWeblate f5cec10e3e Translated using Weblate (Spanish)
Currently translated at 93.2% (8445 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-20 10:13:25 +00:00
Watuneni iteiteandWeblate b6f20c1d75 Translated using Weblate (Japanese)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-02-19 06:59:35 +00:00
geumuandWeblate 750d583770 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-02-17 20:41:32 +00:00
arvid6andWeblate 05f0b439a8 Translated using Weblate (Spanish)
Currently translated at 91.9% (8332 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-17 20:41:32 +00:00
geumuandWeblate 1cb4ffd02f Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-02-17 17:11:34 +00:00
geumuandWeblate 8600d026c3 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-02-17 17:02:57 +00:00
Zack the GhastandWeblate 4e24c764de Translated using Weblate (Portuguese (Portugal))
Currently translated at 70.1% (6355 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-02-16 10:51:45 +00:00
arvid6andWeblate 192d40a475 Translated using Weblate (Spanish)
Currently translated at 91.9% (8328 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-13 15:54:44 +00:00
geumuandWeblate 8c86bb636d Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-02-13 12:12:26 +00:00
arvid6andWeblate 5dc43a8d58 Translated using Weblate (Spanish)
Currently translated at 91.8% (8318 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-13 12:12:25 +00:00
arvid6andWeblate 68a3d7e3b1 Translated using Weblate (Spanish)
Currently translated at 91.8% (8318 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-13 10:26:11 +00:00
Zack the GhastandWeblate 8f4b2c3c0a Translated using Weblate (Portuguese (Portugal))
Currently translated at 69.9% (6334 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-02-11 23:49:07 +00:00
arvid6andWeblate 6645cb68f7 Translated using Weblate (Spanish)
Currently translated at 91.7% (8316 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-11 23:49:06 +00:00
Zack the GhastandWeblate 4c5f330f2a Translated using Weblate (Portuguese (Portugal))
Currently translated at 69.4% (6289 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-02-11 02:22:03 +00:00
arvid6andWeblate 00d445b793 Translated using Weblate (Spanish)
Currently translated at 91.5% (8296 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-11 02:22:01 +00:00
geumuandWeblate cd236c2dea Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-02-10 10:12:12 +00:00
Iván Martín Quinteiro JourdanandWeblate aebf40f78c Translated using Weblate (Spanish)
Currently translated at 89.4% (8107 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-10 10:12:11 +00:00
arvid6andWeblate 52b28fb73f Translated using Weblate (Spanish)
Currently translated at 89.4% (8107 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-10 10:12:11 +00:00
Zack the GhastandWeblate 9b75f20fff Translated using Weblate (Portuguese (Portugal))
Currently translated at 68.9% (6250 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-02-09 11:15:58 +00:00
Nico MerenqandWeblate 56b1fc1149 Translated using Weblate (Russian)
Currently translated at 78.9% (7154 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ru/
2026-02-08 16:22:17 +00:00
阿鱼andWeblate 662ca83a60 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2026-02-08 10:52:27 +00:00
Nico MerenqandWeblate d80ff055f5 Translated using Weblate (Russian)
Currently translated at 77.4% (7015 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ru/
2026-02-08 10:52:26 +00:00
arvid6andWeblate 898f48cf8f Translated using Weblate (Spanish)
Currently translated at 86.8% (7871 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/es/
2026-02-08 10:52:24 +00:00
geumuandWeblate 1688dd42b3 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-02-07 03:20:44 +00:00
geumuandWeblate c4e8fe9c74 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-01-31 15:46:02 +00:00
Zack the GhastandWeblate 3ecaf2dd13 Translated using Weblate (Portuguese (Portugal))
Currently translated at 68.7% (6227 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2026-01-31 01:39:31 +00:00
geumuandWeblate 281afd74e6 Translated using Weblate (Korean)
Currently translated at 100.0% (9061 of 9061 strings)

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ko/
2026-01-31 01:39:30 +00:00
Guilherme Pereira 5b62f608da Merge branch 'main' into evolution-tree 2026-01-27 08:19:06 -03:00
Guilherme Pereira 3840e9cdec Merge branch 'main' into evolution-tree 2025-11-05 09:38:53 -03:00
Guilherme Pereira 5a2ac22bc2 attempt 3 to hide unknown pokemon from evolution tree 2025-10-20 17:44:55 -03:00
Guilherme Pereira 7991662be6 hide name from unknown pokemon in the evolution tree 2025-10-20 15:25:23 -03:00
Guilherme Pereira 8d41c7ae41 evolution tree refactoring 2025-10-20 14:53:17 -03:00
Guilherme Pereira 7768969186 attempt 2 to hide unknow pokemon from evolution tree 2025-10-16 16:54:35 -03:00
Guilherme Pereira 0720ec3565 attempt to hide unknown pokemon from evolution tree 2025-10-15 15:00:36 -03:00
Guilherme Pereira 5d89d9beb6 add support for custom icons and tooltips to the dex evolution tree 2025-10-14 00:02:04 -03:00
Guilherme Pereira 8ee737ae53 Merge branch 'main' into evolution-tree 2025-10-13 22:41:47 -03:00
Guilherme Pereira 886b960572 more requirements 2025-10-13 21:06:03 -03:00
Guilherme Pereira 2d23e88ff3 prevent pcs from exploding 2025-10-12 09:53:52 -03:00
Guilherme Pereira aaa63ebc8a fix wonkiness 2025-10-11 14:44:12 -03:00
Guilherme Pereira b35a82d89e update licenses 2025-10-11 14:32:56 -03:00
Guilherme Pereira 8662d954e3 add expand evolution tree button 2025-10-11 14:30:13 -03:00
Guilherme Pereira 94ddfc8720 add proper handling of variations, shiny and gender to evolution tree 2025-10-10 23:06:53 -03:00
Guilherme Pereira b9fcae2131 add some new requirements to evolution screen 2025-10-10 22:17:32 -03:00
Guilherme Pereira b848f2be3e add some new requirements to evolution screen 2025-10-10 02:00:36 -03:00
Guilherme Pereira f7019c943b add proper handling of mon forms to evolution tree 2025-10-10 00:12:56 -03:00
Guilherme Pereira c933eb2d71 make evolution icon be drawn on top of lines 2025-10-09 02:02:55 -03:00
Guilherme Pereira 09e9946eac add has move type and has friendship to dex evolution tree 2025-10-08 16:16:00 -03:00
Guilherme Pereira 082fcab8b0 add item evolution info to evolution tree 2025-10-08 10:42:45 -03:00
Guilherme Pereira 7bdc8d03b1 add panning to evolution tree 2025-10-07 15:48:27 -03:00
Guilherme Pereira 485e4cfb22 add evolution icon and tooltip for level up evolutions 2025-10-07 10:07:25 -03:00
Guilherme Pereira 4cd69c1b30 center evolution tree based on evolution tree size 2025-10-06 15:52:47 -03:00
Guilherme Pereira 00148452aa implement simple tree drawing algorithm for drawing evolution trees 2025-10-06 11:31:27 -03:00
Guilherme Pereira 598e08b8e6 add pokemon evolution tree page to pokedex 2025-10-03 10:20:13 -03:00
2802 changed files with 152523 additions and 25876 deletions
+1
View File
@@ -24,6 +24,7 @@ eclipse
run
runClient
runServer
utilityscripts/implementation/*.txt
# Files from Forge MDK
forge*changelog.txt
+2 -2
View File
@@ -71,8 +71,8 @@ setup_packsquash:
- echo "Installing wget & unzip"
- yum install -y wget unzip
- echo "Downloading PackSquash"
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.0/PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip
- unzip PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip -d ./packsquash_bin
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.1/packsquash-x86_64-unknown-linux-musl.zip
- unzip packsquash-x86_64-unknown-linux-musl.zip -d ./packsquash_bin
- echo "Creating PackSquash options.toml"
- |
cat <<EOF > ./options.toml
+251 -33
View File
@@ -53,80 +53,161 @@
- All shipwreck coves' spawners have been adjusted to give compatible mobs enchanted iron or diamond armour and weapons while in its ominous state. The armour given to the mobs will also use the automaton trim. We upped the difficulty because it was too easy now that your Pokémon can fight for you.
- One TM of the elemental hyper beams has been added as guaranteed loot to the main treasure chest in every shipwreck cove. (Magma cove gets blast burn, lush cove gets frenzy plant, and submerged cove gets hydro cannon)
- Added 7 new advancements
- Pressing the inventory key now closes the Pokémon interact wheel GUI
- Pokémon cries now play when clicking Pokémon in the summary screen.
- Pressing the Summary key while either the starter selection or summary screen are open now closes those screens
- Ice type Pokémon are now immune to Packed Snow
### New rideable Pokémon
- Drampa
- Archeops
- Skarmory
- Crobat
- Goodra
- Hisuian Goodra
- Milotic
### Pokémon Added
- Pancham (+ Cosmetic with Black Glasses)
- Pangoro (+ Cosmetic with Black Glasses)
- Skitty
- Delcatty
#### Generation 3
- Wurmple
- Silcoon
- Beautifly
- Cascoon
- Dustox
- Skitty
- Delcatty
- Seviper
- Zangoose
#### Generation 4
- Cherubi
- Cherrim
- Stunky
- Skuntank
#### Generation 5
- Audino
- Pawniard
- Bisharp
#### Generation 6
- Pancham (+ Cosmetic with Black Glasses)
- Pangoro (+ Cosmetic with Black Glasses)
#### Generation 7
- Rockruff
- Lycanroc
#### Generation 8
- Rolycoly
- Carkol
- Coalossal
- Runerigus
- Snom
- Frosmoth
- Indeedee
- Duraludon
- Applin
- Flapple
- Appletun
- Dipplin
- Hydrapple
- Sandshrew (Alolan)
- Sandslash (Alolan)
- Seviper
- Zangoose
- Stunky
- Skuntank
- Pawniard
- Bisharp
#### Generation 9
- Nymble
- Lokix
- Kingambit
- Dipplin
- Archaludon
- Hydrapple
#### Regional Forms
- Sandshrew (Alolan Form)
- Sandslash (Alolan Form)
- Yamask (Galarian Form)
- Avalugg (Hisuian Form)
### Model updates for the following Pokémon
- Goomy
- Sliggoo
- Goodra
- Porygon
- Porygon2
- Porygon-Z
- Sandshrew
- Sandslash
- Nidoking
- Zubat
- Golbat
- Crobat
- Pidgey
- Pidgeotto
- Pidgeot
- Sandslash
- Nidoking
- Ditto
- Porygon
- Porygon2
- Porygon-Z
- Skarmory
- Smoochum
- Jynx
- Popplio
- Brionne
- Primarina
- Fletchling
- Fletchinder
- Talonflame
- Sableye
- Mawile
- Goomy
- Sliggoo
- Goodra
- Nacli
- Naclestack
- Naclstack
- Garganacl
- Skarmory
- Bidoof
- Cranidos
- Chatot
- Yamask
- Cofagrigus
- Tyranitar
- Turtonator
- Arbok (New Patterns: Angry, Cartoon, Clown, Comedic, Crow, Grin, Ink, Modern, Rain, Scribble, Silence, Sloth, Suspicious, Will)
#### Model changes to the regional bias resource pack:
- Added Mime Jr. (Galar Bias)
- Added Bergmite (Hisui Bias)
- Changed models for every existing regional bias
### Animation updates for the following Pokémon
- Drampa
- Archeops
- Skarmory
- Skitty
- Flygon
- Shellos
- Riolu
- Lucario
- Shellos
- Skitty
- Joltik
- Purrloin
- Liepard
- Flygon
- Joltik
- Galvantula
- Nidoking
- Fletchling
- Fletchinder
- Talonflame
- Archeops
- Drampa
- Sewaddle
- Swadloon
- Leavanny
- Goomy
- Sliggoo
- Goodra
- Shedinja
- Skwovet
- Greedent
- Bidoof
- Cranidos
- Chatot
- Yamask
- Cofagrigus
- Luvdisc
#### Added sounds to the following moves
- Absorb
- Aurora Beam
- Double Team
- Draco Meteor
- Fire Punch
- Fire Spin
- Flame Charge
@@ -146,10 +227,19 @@
- Tail Whip
### Changes
- Stat increase and decrease particles have been changed, with the addition of alpha boost particles.
- Dragonite's mailbag cosmetic can now also be obtained with a chest in the cosmetic slot
### Fixes
- Adjusted Croagunk's walkspeed
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly
- Fixed Litleo not blinking
- Fixed Garchomp T-posing when sleeping while out of battle.
- Sharp Beak can now be crafted
- Metal Alloy can now be crafted
- Ability Capsules can now be brewed
- Using an Ability Capsule will now return an Empty Bottle
- The following items can now be obtained by brushing the following Pokémon:
- Pink Wool - Wigglytuff
- White Wool - Swablu, Altaria
@@ -173,6 +263,43 @@
- Cleaned up seat data. Removed all now unused fields from seats in all species files. Also made locator seat names explicit in the species files (however, this doesn't break the legacy format)
- Marks can now provide aspects.
- Added new shiny and Alpha chance configs
- Apricorns now make a new sound when harvested
- Lowered the volume of harvesting berries
- Added alternate versions of the basic PC Wallpapers based on the original design of Cobblemon's PC, before public release
- Improved compatibility with various mods
- Farmer's Delight's cutting board can now be used to strip Apricorn and Saccharine's logs, or salvage their planks from various blocks. It can also separate their boats from chests
- Farmer's Delight's cutting board can be used to get two white dye from Pep-Up Flowers and two magenta dye from Medicinal Leeks
- Farmer's Delight's cutting board can separate Tumblestone Blocks back into Tumblestones
- Farmer's Delight's cutting board can salvage Type Gems from their Gem Blocks
- Farmer's Delight's Onions, Tomatoes, and Cabbages can be used to cook Open-Faced Sandwiches. Nature's Spirit's Olives also can be used
- Farmer's Delight's cutting board can be used on Hearty Grains to obtain rice and straw, similarly to Farmer's Delight's Rice Panicles
- Farmer's Delight's Apple Pies and Apple Ciders can now be made using Applin Apples, alongside the Vanilla counterpart
- Amendments allows for cooking Leek and Potato Stew in a Cauldron
- Any mods that utilise Moonlight's Soft Fluid system can store Leek and Potato Stew, Medicinal Brew, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Ability Capsules, Moomoo Milk, and Berry Juice in liquid form (such as Suplementaries' Jar or Goblet, or Cauldrons while using Amendments)
- Supplementaries' Hourglass can now use Bright Powder, Quick Powder, Metal Powder, Heal Powder, Silver Powder, and Remedy
- Berry Trees are now compatible with the Planter properly
- Saccharine Way Signs (added by Supplementaries automagically) now use a premade texture to prevent odd visual issues
- Supplementaries' Jar can now store various Cobblemon cookies, candies, and similar items
- Some of Supplementaries' items have been added to the `#cobblemon:held/container_held_items` item tag, including sacks, safes, and lunch baskets
- Experience Nuggets can be used in place of Sculk for making the EXP Candies if using Create
- Rage Candy Bar has a Create Mixing recipe
- All Cobblemon ores can now be crushed in Create's Crushing Wheels
- All Gem and Tumblestone Clusters can be crushed for automatic, low return, gems
- Hearty Grains can be milled like Farmer's Delight Rice Panicles if both Farmer's Delight and Create are installed
- Big Roots and Revival Herbs can be milled to their respective powders
- Pep-Up Flowers, Medicinal Leeks, and all 70 berries can be milled in Create's Millstone for additional dye drops
- Auspicious Armor and Upgrades can be Haunted using Create's crafting systems
- Applin Apples can be used to make Honeyed Apples in Create
- Golden Apples can now be crafted using the Applin Apples
- Prismarine Crystals and Amethyst Shards can now be used to craft Pokedexes
- Updated Pokedex Screens item tag to support tagged variants of Redstone and Glowstone Dust
- Sounds for interacting with various Cobblemon blocks now play from the center of the block, rather than the corner
- The `/pc` command no longer plays PC activation sounds
- Lowered the volume of Blitzle and Zebstrika's cry
- Fixed Raichu (male) and Alolan Raichu (both genders) not displaying the correct Partner Cap when Pewter Crunchies are in the cosmetic slot.
- Regional Foods will now prioritize being eaten instead of used for healing Pokémon, shift clicking will use it as healing
- Resolved Z-Fighting on Pokédex Models
- Restored Ninjask's ability to do barrel rolls
### Fixes
- Fixed Croagunk's walkspeed
@@ -184,6 +311,7 @@
- Fixed a compatibility issue with World Game Rules which caused some log spam in specific cases.
- Fixed improper validation of Pokémon when performing a trade.
- Fixed an issue where particle like beam can disappear when you don't see the beginning of the beam, or you look away
- Fixed Bedrock particle materials (alpha/opaque/blend/add) sharing one render batch, which caused incorrect culling on mixed batches; each material now batches and draws with its own blend and cull state, and the alpha material renders as a true cutout
- Fixed an occasional crash on retrieving revived fossils
- Fixed brushing not working on Neoforge
- Fixed braking not working for submarines (whoops).
@@ -211,6 +339,17 @@
- Fixed various log warnings caused by redundant files and sound events.
- Traded Pokémon will now retain the original friendship level when traded back to its OT
- Clusters now display correctly on maps
- Fixed removing mulch from berry trees with a shovel not working.
- Fixed collecting honey from Saccharine Leaf blocks deleting Honey Bottles when the inventory was full
- Fixed Stripped Saccharine Wood recipe being missing
- Fixed CancelableSoundInstance causing lag by attempting to create sounds every tick when out of range of hearing
- Fixed Stat Reducing Aprijuice not being possible to apply on a max out Pokémon, and the possibility of going into negatives
- Fixed Exploit where you could take out the bait or drop your Pokérod with bait to avoid consuming bait, now the bobber will just disappear if you do so
- Fixed Apricorn and Saccharine boats incorrectly using chest boat models
- Fixed wild and trainer battle AI refusing to select moves with the `adjacentAlly` target type, even when it's their only option
- Fixed Guilded chests being more accessible than intended
- Fixed fished up Pokémon not being added as "seen" to the Pokedex
- Fixed surprised Gimmighoul encounters not being added as "seen" to the Pokedex
### Developer
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters
@@ -219,6 +358,8 @@
- Tweaked the spawning selector interface to take a bucket function rather than a bucket directly.
- Added a new `cobblemon:height_range` processor type to allow developers to restrict structure-spawning ranges.
- Separated all the functions of MoLangFunctions.kt into their own files.
- Spawn buckets and their base weights are now provided by the spawner, with different base weights for world, fishing, snack, and habitat spawn buckets.
- Removed "SpawnBucket" class in favour of just storing maps of bucket names to weights.
### Molang & Datapacks
- Added `moveset_builders` datapack folder for different styles of movesets.
@@ -241,8 +382,85 @@
- Ride sounds can now be set as exclusive to passengers
- Ride sounds no longer play when submerged unless specified with a new setting
- NPC Trainers can now call a `command` animation when issuing a command in battle.
- Added a q.failed function to move action effects.
- Herd spawned Pokémon have their levels controlled differently. The `levelRange` property now acts as a clamp instead of a filter, with a new `herdLevelRange` property to do the filter behaviour.
- `q.sound` now accepts three parameters (sound event, volume and pitch) instead of just the sound event and pitch.
### Particles
#### New Move Animations
- Blizzard
- Disarming Voice
- Draco Meteor
- Dragon Breath
- Dragon Rage
- Drain Punch
- Fairy Wind
- Fire Fang
- Gust
- Horn Drill
- Hydro Pump
- Ice Fang
- Leafage
- Leaf Storm
- Light Screen
- Night Shade
- Play Rough
- Pyro Ball
- Reflect
- Rock Slide
- Sonic Boom
- Sucker Punch
- Supersonic
- Thunder Fang
#### Tweaks and Fixes (Moves)
- Confusion
- Dragon Claw
- Eruption
- Fire Punch
- Flame Burst
- Flame Charge
- Flamethrower
- Frost Breath
- Hypnosis
- Ice Punch
- Icy Wind
- Mud Sport
- Poison Fang
- Protect
- Psychic
- Quick Attack
- Rage Powder
- Razor Leaf
- Sand Attack
- Scratch
- Shadow Claw
- Sing
- Spore
- String Shot
- Tackle
- Tail Whip
- Thunder
- Thunder Punch
- Thunder Wave
- Water Gun
- Water Pulse
- Water Sport
#### Miscellaneous Particles
+ Added Wild Might particles for Alpha Pokémon
+ Updated stat increase and decrease particles
### Localization
- Updated translations for:
- Japanese
- German
- Spanish
- Ecuadorian Spanish
- Brazilian Portuguese
- Simplified Chinese
- Traditional Chinese
- Korean
+4
View File
@@ -72,6 +72,10 @@ tasks.withType<Test> {
}
}
tasks.processResources {
exclude("data/**/README.md")
}
sourceSets {
main {
blossom {
@@ -0,0 +1,111 @@
/*
* 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.mixin.accessor.SinglePoolElementAccessor;
import com.cobblemon.mod.common.world.structureprocessors.HeightRangeStructureProcessor;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.pools.*;
import net.minecraft.world.level.levelgen.structure.pools.alias.PoolAliasLookup;
import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
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.CallbackInfoReturnable;
import java.util.Optional;
@Mixin(JigsawPlacement.class)
public class JigsawPlacementMixin {
@Inject(
method = "addPieces(Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;Lnet/minecraft/core/Holder;Ljava/util/Optional;ILnet/minecraft/core/BlockPos;ZLjava/util/Optional;ILnet/minecraft/world/level/levelgen/structure/pools/alias/PoolAliasLookup;Lnet/minecraft/world/level/levelgen/structure/pools/DimensionPadding;Lnet/minecraft/world/level/levelgen/structure/templatesystem/LiquidSettings;)Ljava/util/Optional;",
at = @At("RETURN"),
cancellable = true
)
private static void onAddPieces(
Structure.GenerationContext context,
Holder<StructureTemplatePool> startPool,
Optional<ResourceLocation> startJigsawName,
int maxDepth,
BlockPos pos,
boolean useExpansionHack,
Optional<Heightmap.Types> projectStartToHeightmap,
int maxDistanceFromCenter,
PoolAliasLookup aliasLookup,
DimensionPadding dimensionPadding,
LiquidSettings liquidSettings,
CallbackInfoReturnable<Optional<Structure.GenerationStub>> cir
) {
Optional<Structure.GenerationStub> result = cir.getReturnValue();
if (result.isEmpty()) {
return;
}
BlockPos spawnPos = result.get().position();
boolean canPlace = cobblemon$canAnyStartElementPlace(context, startPool, spawnPos);
if (canPlace) {
return;
}
cir.setReturnValue(Optional.empty());
}
@Unique
private static boolean cobblemon$canAnyStartElementPlace(
Structure.GenerationContext generationContext,
Holder<StructureTemplatePool> startPool,
BlockPos startPos
) {
for (StructurePoolElement element : startPool.value().templates) {
Optional<HeightRangeStructureProcessor> heightRangeProcessor = cobblemon$getHeightRangeProcessor(element);
if (heightRangeProcessor.isEmpty()) {
return true;
}
HeightRangeStructureProcessor processor = heightRangeProcessor.get();
boolean valid = processor.isValidPlacement(
generationContext.chunkGenerator(),
generationContext.heightAccessor(),
generationContext.randomState(),
startPos
);
if (valid) {
return true;
}
}
return false;
}
@Unique
private static Optional<HeightRangeStructureProcessor> cobblemon$getHeightRangeProcessor(StructurePoolElement element) {
if (!(element instanceof SinglePoolElement)) {
return Optional.empty();
}
StructureProcessorList processorList = ((SinglePoolElementAccessor) element).getProcessors().value();
for (StructureProcessor processor : processorList.list()) {
if (processor instanceof HeightRangeStructureProcessor heightRangeStructureProcessor) {
return Optional.of(heightRangeStructureProcessor);
}
}
return Optional.empty();
}
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.core.Holder;
import net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(SinglePoolElement.class)
public interface SinglePoolElementAccessor {
@Accessor("processors")
Holder<StructureProcessorList> getProcessors();
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.duck.ChannelDuck;
import com.mojang.blaze3d.audio.Channel;
@@ -308,7 +308,9 @@ object Cobblemon {
this.config.maxPokemonLevel,
this.config.maxPokemonFriendship,
this.config.maxDynamaxLevel,
this.config.unlockAllMoveDexMovesByDefault
this.config.unlockAllMoveDexMovesByDefault,
this.config.pokemonIntrinsicSizeMin,
this.config.pokemonIntrinsicSizeMax
).sendToPlayer(player)
}
@@ -131,6 +131,7 @@ import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangeP
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
@@ -439,6 +440,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -108,6 +108,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val LEVELUP = this.create("gui.levelup")
@JvmField
val MOVE_LEARN = this.create("gui.move_learn")
@JvmField
val PVN_BATTLE = this.create("battle.pvn.default")
@JvmField
@@ -212,17 +215,23 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val TM_USE = this.create("item.tm.use")
@JvmField
val TM_MACHINE_BURN_LOOP = this.create("block.tm_machine.burn_loop")
@JvmField
val TM_MACHINE_CRAFT = this.create("block.tm_machine.craft")
@JvmField
val TM_MACHINE_OFF = this.create("block.tm_machine.off")
@JvmField
val TM_MACHINE_ON = this.create("block.tm_machine.on")
val TM_MACHINE_START = this.create("block.tm_machine.start")
@JvmField
val TM_MACHINE_OPEN = this.create("block.tm_machine.open")
@JvmField
val TM_MACHINE_CLOSE = this.create("block.tm_machine.close")
@JvmField
val TM_MACHINE_PLACE_DISC = this.create("block.tm_machine.place_disc")
val TM_MACHINE_TM_INSERT = this.create("block.tm_machine.tm_insert")
@JvmField
val TM_MACHINE_TM_RETRIEVE = this.create("block.tm_machine.tm_retrieve")
@JvmField
val TM_MACHINE_ITEM_INSERT = this.create("block.tm_machine.item_insert")
@JvmField
val TM_MACHINE_ITEM_RETRIEVE = this.create("block.tm_machine.item_retrieve")
@JvmField
@@ -263,6 +272,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val BERRY_EAT_FULL = this.create("item.berry.eat.full")
@JvmField
val APRICORN_HARVEST = this.create("block.apricorn.harvest")
@JvmField
val BIG_ROOT_BREAK = this.create("block.big_root.break")
@JvmField
@@ -410,9 +422,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
)
@JvmField
val TYPE_GEM_BLOCK_BREAK = this.create("block.type_gem_cluster.break")
val TYPE_GEM_BLOCK_BREAK = this.create("block.type_gem_block.break")
@JvmField
val TYPE_GEM_CLUSTER_BREAK = this.create("block.type_gem_block.break")
val TYPE_GEM_CLUSTER_BREAK = this.create("block.type_gem_cluster.break")
@JvmField
val TYPE_GEM_BLOCK_HIT = this.create("block.type_gem_block.hit")
@JvmField
@@ -421,7 +433,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
val TYPE_GEM_BLOCK_STEP = this.create("block.type_gem_block.step")
@JvmField
val TYPE_GEM_CLUSTER_SOUNDS = SoundType(1f, 1.2f,
val TYPE_GEM_CLUSTER_SOUNDS = SoundType(1f, 1.1f,
TYPE_GEM_CLUSTER_BREAK,
TYPE_GEM_BLOCK_STEP,
TYPE_GEM_BLOCK_PLACE,
@@ -48,7 +48,7 @@ class RidingStatBoostCriterion(
val max = context.pokemon.pokemon.getMaxRideBoost(rideStat).toDouble()
val min = context.pokemon.pokemon.getBaseRideStat(rideStat).toDouble()
val value = context.pokemon.getRideStat(rideStat, ridingStyle, min, max)
val isSufficient = (value >= this.statValue && this.statValue > 0.0) || !context.pokemon.pokemon.canAddRideBoost(rideStat)
val isSufficient = (value >= this.statValue && this.statValue > 0.0) || !context.pokemon.pokemon.canApplyRideBoost(rideStat)
if (isSufficient && this.rideStat == "any") {
return true
} else if (!isSufficient && this.rideStat == "all") {
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.data
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
// TODO this is implemented in multiple places but unused. Can we scratch this?
/**
* Represents an object that will possibly be synchronized to the client during datapack synchronization.
*
* @param T The type of the object being synchronized.
*
* @author Licious
* @since October 14th, 2022
*/
interface ClientDataSynchronizer<T> : Decodable, Encodable {
/**
* Compares an object of type [T] with this instance to see if synchronization is necessary.
*
* @param other The other instance of type [T].
* @return If synchronization is necessary.
*/
fun shouldSynchronize(other: T): Boolean
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.events.entity
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
@@ -21,7 +20,7 @@ class SpawnBucketChosenEvent(
/** The cause of the spawn. */
val spawnCause: SpawnCause,
/** The bucket that was chosen. You can alter this. */
var bucket: SpawnBucket,
var bucket: String,
/** The final weights that were used to make the choice. */
val bucketWeights: Map<SpawnBucket, Float>
val bucketWeights: Map<String, Float>
)
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.events.fishing
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.world.item.ItemStack
@@ -27,7 +26,7 @@ interface BaitSpawnPokemonEvent {
*/
data class Pre(
val bobber: PokeRodFishingBobberEntity, // todo replace this with the bait entity
val chosenBucket: SpawnBucket,
val chosenBucket: String,
val rod: ItemStack
) : Cancelable(), BobberSpawnPokemonEvent
@@ -38,7 +37,7 @@ interface BaitSpawnPokemonEvent {
* @param pokemon The Pokemon that is modified.
*/
data class Modify(
val chosenBucket: SpawnBucket,
val chosenBucket: String,
val rod: ItemStack,
val pokemon: PokemonEntity
) : BobberSpawnPokemonEvent
@@ -52,7 +51,7 @@ interface BaitSpawnPokemonEvent {
*/
data class Post(
val bobber: PokeRodFishingBobberEntity,
val chosenBucket: SpawnBucket,
val chosenBucket: String,
val bait: ItemStack,
val pokemon: PokemonEntity
) : BobberSpawnPokemonEvent
@@ -8,12 +8,10 @@
package com.cobblemon.mod.common.api.events.fishing
import com.cobblemon.mod.common.api.spawning.SpawnBucket
/**
* Event that is fired when a bucket is chosen by the bobber.
* @param chosenBucket The bucket that is chosen.
* @param buckets The list of buckets that the bobber can choose from.
* @param luckOfTheSeaLevel The level of the Luck of the Sea enchantment on the rod.
*/
class BobberBucketChosenEvent(var chosenBucket: SpawnBucket, val buckets: MutableList<SpawnBucket>, val luckOfTheSeaLevel: Int)
class BobberBucketChosenEvent(var chosenBucket: String, val buckets: MutableList<String>, val luckOfTheSeaLevel: Int)
@@ -12,10 +12,7 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
@@ -73,8 +70,8 @@ interface BobberSpawnPokemonEvent {
val bait: ItemStack,
val pokemon: PokemonEntity
) : BobberSpawnPokemonEvent {
val context = mutableMapOf<String, MoValue>(
"chosen_bucket" to ObjectValue(spawnAction.bucket, { it.name }),
val context = mutableMapOf(
"chosen_bucket" to StringValue(spawnAction.bucket),
"bait" to pokemon.level().itemRegistry.wrapAsHolder(bait.item).asMoLangValue(Registries.ITEM),
"pokemon_entity" to pokemon.asMoLangValue()
)
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.gui
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import net.minecraft.client.gui.components.AbstractWidget
import net.minecraft.client.gui.components.Renderable
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.gui.narration.NarrationElementOutput
import net.minecraft.network.chat.Component
@@ -55,6 +54,8 @@ abstract class ParentWidget(
}
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
if (!active) return false
return children.any {
it.mouseClicked(pMouseX, pMouseY, pButton)
}
@@ -0,0 +1,116 @@
/*
* 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.gui
import kotlin.math.max
import kotlin.math.min
interface TreeNode<T> {
val children: List<TreeNode<T>>
}
class TreeDrawingNode<T>(
val value: T,
val children: List<TreeDrawingNode<T>>,
) {
var x = 0
var y = 0
var offset = 0
}
fun <T> createDrawingTree(treeNode: TreeNode<T>): TreeDrawingNode<T> {
val root = setup(treeNode, 0, mutableListOf<Int>(), mutableListOf<Int>())
addMods(root, 0)
return root
}
@Suppress("UNCHECKED_CAST")
private fun <T> setup(
treeNode: TreeNode<T>,
depth: Int,
nexts: MutableList<Int>,
offset: MutableList<Int>,
): TreeDrawingNode<T> {
val children = treeNode.children.map { child ->
setup(child, depth + 1, nexts, offset)
}
val treeDrawingNode = TreeDrawingNode<T>(treeNode as T, children)
treeDrawingNode.y = depth
while (nexts.size <= depth) {
nexts.add(0)
}
while (offset.size <= depth) {
offset.add(0)
}
var place =
if (children.isEmpty()) {
nexts[depth]
} else if (children.size == 1) {
// children.first().x - 1
children.first().x
} else {
// (children[0].x + children[1].x) / 2
(children.first().x + children.last().x) / 2
}
offset[depth] = max(offset[depth], nexts[depth] - place)
if (children.isEmpty()) {
treeDrawingNode.x = place
} else {
treeDrawingNode.x = place + offset[depth]
}
nexts[depth] += 2
treeDrawingNode.offset = offset[depth]
return treeDrawingNode
}
private fun <T> addMods(
treeNode: TreeDrawingNode<T>,
modSum: Int,
) {
treeNode.x += modSum
val newModSum = modSum + treeNode.offset
treeNode.children.forEach { child ->
addMods(child, newModSum)
}
}
data class TreeDrawingBounds(val minX: Int, val maxX: Int, val minY: Int, val maxY: Int) {
val width = maxX - minX
val height = maxY - minY
val xCenter = (maxX + minX) / 2.0
val yCenter = (maxY + minY) / 2.0
}
fun <T> calculateBounds(treeDrawingNode: TreeDrawingNode<T>): TreeDrawingBounds {
var minX = treeDrawingNode.x
var maxX = treeDrawingNode.x
var minY = treeDrawingNode.y
var maxY = treeDrawingNode.y
for (child in treeDrawingNode.children) {
val childBounds = calculateBounds(child)
minX = min(minX, childBounds.minX)
maxX = max(maxX, childBounds.maxX)
minY = min(minY, childBounds.minY)
maxY = max(maxY, childBounds.maxY)
}
return TreeDrawingBounds(minX, maxX, minY, maxY)
}
@@ -1,37 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.habitats
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* A [HabitatPool] of [ActivatedHabitatSpawn]s. Mainly just to help with deserialization and ensuring
* a single type for everything that's applied to a habitat block.
*
* @author Hiroku
* @since February 13th, 2026
*/
class ActivatedHabitatPool : HabitatPool<ActivatedHabitatSpawn>() {
override val type: ResourceLocation = ActivatedHabitatSpawn.TYPE
override var spawns: List<ActivatedHabitatSpawn> = listOf()
companion object {
fun default() = ActivatedHabitatPool().apply {
id = ResourceLocation("cobblemon", "custom__default_activated_pool")
name = "Custom"
}
}
override fun decode(buffer: RegistryFriendlyByteBuf, buckets: List<SpawnBucket>) {
super.decode(buffer, buckets)
spawns = buffer.readList { ActivatedHabitatSpawn().apply { decode(buffer, buckets) } }
}
}
@@ -1,23 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.habitats
import com.cobblemon.mod.common.util.cobblemonResource
/**
* A basic [HabitatSpawn] that will be triggered via activated spawning in a habitat. Nothing to it, really.
*
* @author Hiroku
* @since February 13th, 2026
*/
class ActivatedHabitatSpawn : HabitatSpawn() {
companion object {
val TYPE = cobblemonResource("activated")
}
}
@@ -8,39 +8,81 @@
package com.cobblemon.mod.common.api.habitats
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* A pool of [HabitatSpawn]s. This is either filled with [NaturalHabitatSpawn]s or [ActivatedHabitatSpawn]s depending
* on whether the pool is a [NaturalHabitatPool] or an [ActivatedHabitatPool]. The pool is responsible for converting
* A pool of [HabitatSpawn]s. This is filled with [HabitatSpawn]s. The pool is responsible for converting
* its spawns into [PokemonSpawnDetail]s.
*
* @author Hiroku
* @since February 13th, 2026
*/
abstract class HabitatPool<T : HabitatSpawn> {
class HabitatPool {
companion object {
val types = mutableMapOf(
ActivatedHabitatSpawn.TYPE to ActivatedHabitatPool::class.java,
NaturalHabitatSpawn.TYPE to NaturalHabitatPool::class.java
)
fun default() = HabitatPool().apply {
id = ResourceLocation("cobblemon", "custom__default_pool")
name = "Custom"
}
fun writePoolToNBT(pool: HabitatPool, nbt: CompoundTag) {
nbt.putString(DataKeys.HABITAT_POOL_ID, pool.id.toString())
if (pool.id.path.startsWith("custom__")) {
nbt.putString(DataKeys.HABITAT_POOL_NAME, pool.name)
val spawnsListNBT = ListTag()
for (spawn in pool.spawns) {
val spawnTag = CompoundTag()
spawn.writeToNBT(spawnTag)
spawnsListNBT.add(spawnTag)
}
nbt.put(DataKeys.HABITAT_POOL_SPAWNS, spawnsListNBT)
}
}
fun readPoolFromNBT(nbt: CompoundTag): HabitatPool {
val poolId = nbt.getString(DataKeys.HABITAT_POOL_ID).asIdentifierDefaultingNamespace()
if (nbt.contains(DataKeys.HABITAT_POOL_NAME)) {
// It's one that was stored on the block
val pool = HabitatPool()
pool.id = poolId
pool.name = nbt.getString(DataKeys.HABITAT_POOL_NAME)
val spawnsListNBT = nbt.getList(DataKeys.HABITAT_POOL_SPAWNS, Tag.TAG_COMPOUND.toInt())
val spawns = mutableListOf<HabitatSpawn>()
spawnsListNBT.forEach { spawnTag ->
try {
val spawn = HabitatSpawn().apply { readFromNBT(spawnTag as CompoundTag) }
spawns.add(spawn)
} catch (_: Exception) {
// If there's an error reading a spawn, skip it and log the error.
Cobblemon.LOGGER.error("Error reading activated habitat spawn from NBT for habitat block, skipping.")
}
}
pool.spawns = spawns
return pool
} else {
return HabitatPools.habitatPoolsById[poolId] ?: HabitatPool.default()
}
}
}
lateinit var id: ResourceLocation
var name: String = ""
abstract val type: ResourceLocation
abstract var spawns: List<T>
var spawns: List<HabitatSpawn> = listOf()
/** Whether a pool is editable is just down to whether it's not from a datapack. */
@Transient
var editable: Boolean = false
open fun validate() {
fun validate() {
for (spawn in spawns) {
if (SpawnablePosition.getByName(spawn.spawnablePositionType) == null) {
throw IllegalArgumentException("$id mentions non-existent spawnable position type ${spawn.spawnablePositionType} on spawn for ${spawn.species}")
@@ -58,8 +100,9 @@ abstract class HabitatPool<T : HabitatSpawn> {
buffer.writeCollection(spawns) { _, it -> it.encode(buffer) }
}
open fun decode(buffer: RegistryFriendlyByteBuf, buckets: List<SpawnBucket>) {
fun decode(buffer: RegistryFriendlyByteBuf) {
id = buffer.readResourceLocation()
name = buffer.readUtf()
spawns = buffer.readList { HabitatSpawn().apply { decode(buffer) } }
}
}
@@ -12,16 +12,13 @@ import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.spawning.IntRanges
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.TimeRange
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.adapters.HabitatPoolAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
import com.cobblemon.mod.common.util.adapters.RegisteredSpawnablePositionAdapter
import com.cobblemon.mod.common.util.adapters.SpawnBucketAdapter
import com.cobblemon.mod.common.util.adapters.SpeciesAdapter
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
import com.cobblemon.mod.common.util.cobblemonResource
@@ -36,18 +33,16 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.level.storage.LevelResource
object HabitatPools : JsonDataRegistry<HabitatPool<*>> {
object HabitatPools : JsonDataRegistry<HabitatPool> {
override val id = cobblemonResource("habitat_pools")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<HabitatPools>()
override val typeToken: TypeToken<HabitatPool<*>> = TypeToken.get(HabitatPool::class.java)
override val typeToken: TypeToken<HabitatPool> = TypeToken.get(HabitatPool::class.java)
override val resourcePath = "habitat_pools"
override val gson: Gson = GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(HabitatPool::class.java, HabitatPoolAdapter)
.registerTypeAdapter(SpawnablePositionType::class.java, RegisteredSpawnablePositionAdapter)
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
.registerTypeAdapter(Species::class.java, SpeciesAdapter)
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
.registerTypeAdapter(TimeRange::class.java, TimeRange.adapter)
@@ -56,10 +51,10 @@ object HabitatPools : JsonDataRegistry<HabitatPool<*>> {
.setPrettyPrinting()
.create()
private val datapacked = mutableMapOf<ResourceLocation, HabitatPool<*>>()
private val worldSaved = mutableMapOf<ResourceLocation, HabitatPool<*>>()
private val datapacked = mutableMapOf<ResourceLocation, HabitatPool>()
private val worldSaved = mutableMapOf<ResourceLocation, HabitatPool>()
val habitatPoolsById = mutableMapOf<ResourceLocation, HabitatPool<*>>()
val habitatPoolsById = mutableMapOf<ResourceLocation, HabitatPool>()
private lateinit var worldSavedPoolsFolder: File
@@ -73,7 +68,7 @@ object HabitatPools : JsonDataRegistry<HabitatPool<*>> {
worldSavedPoolsFolder.listFiles { it.endsWith(".json") }.forEach {
val identifier = ResourceLocation.parse(it.nameWithoutExtension)
val habitat = gson.fromJson<HabitatPool<*>>(it.reader())
val habitat = gson.fromJson<HabitatPool>(it.reader())
habitat.id = identifier
habitat.validate()
habitat.editable = true
@@ -82,7 +77,7 @@ object HabitatPools : JsonDataRegistry<HabitatPool<*>> {
setupHabitatPoolsById()
}
override fun reload(data: Map<ResourceLocation, HabitatPool<*>>) {
override fun reload(data: Map<ResourceLocation, HabitatPool>) {
datapacked.clear()
datapacked.putAll(data)
data.entries.forEach { (identifier, habitat) ->
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.api.habitats
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.IntRanges
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.TimeRange
import com.cobblemon.mod.common.api.spawning.condition.AppendageCondition
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
@@ -30,9 +28,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.network.RegistryFriendlyByteBuf
/**
* A kind of simplified spawn definition for the purposes of spawning from [HabitatBlockEntity] instances. This is a
* very shallow class tree, with [ActivatedHabitatSpawn] being a trivial subclass but the other subclass being
* [NaturalHabitatSpawn] which introduces the need to supply a spawn bucket.
* A kind of simplified spawn definition for the purposes of spawning from [HabitatBlockEntity] instances.
*
* These have only a small subset of the properties that a regular [PokemonSpawnDetail] would have to align with the
* fact that these are configured from a simple GUI. There are limits to how many properties and conditions could be
@@ -46,11 +42,13 @@ import net.minecraft.network.RegistryFriendlyByteBuf
* @author Hiroku
* @since February 13th, 2026
*/
sealed class HabitatSpawn {
class HabitatSpawn {
/** The species that will be spawned. */
lateinit var species: Species
/** The kind of position the Pokémon will spawn in. Things like "grounded", "seafloor", "fishing". */
lateinit var spawnablePositionType: String
/** The bucket to spawn from. */
var bucket: String = "common"
/** Selection weight. */
var weight: Float = 1F
@@ -77,6 +75,7 @@ sealed class HabitatSpawn {
timeRange?.let { nbt.putString(DataKeys.HABITAT_POOL_SPAWN_TIMES, TimeRange.adapter.serialize(it)) }
minLight?.let { nbt.putInt(DataKeys.HABITAT_POOL_SPAWN_MIN_LIGHT, it) }
maxLight?.let { nbt.putInt(DataKeys.HABITAT_POOL_SPAWN_MAX_LIGHT, it) }
nbt.putString(DataKeys.HABITAT_POOL_SPAWN_BUCKET, bucket)
}
open fun readFromNBT(nbt: CompoundTag) {
@@ -89,6 +88,7 @@ sealed class HabitatSpawn {
timeRange = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_TIMES)) TimeRange.adapter.deserialize(nbt.getString(DataKeys.HABITAT_POOL_SPAWN_TIMES)) else null
minLight = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_MIN_LIGHT)) nbt.getInt(DataKeys.HABITAT_POOL_SPAWN_MIN_LIGHT) else null
maxLight = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_MAX_LIGHT)) nbt.getInt(DataKeys.HABITAT_POOL_SPAWN_MAX_LIGHT) else null
bucket = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_BUCKET)) nbt.getString(DataKeys.HABITAT_POOL_SPAWN_BUCKET) else "common"
}
open fun encode(buffer: RegistryFriendlyByteBuf) {
@@ -101,12 +101,10 @@ sealed class HabitatSpawn {
buffer.writeNullable(timeRange) { _, value -> buffer.writeUtf(TimeRange.adapter.serialize(value)) }
buffer.writeNullable(minLight) { _, value -> buffer.writeInt(value) }
buffer.writeNullable(maxLight) { _, value -> buffer.writeInt(value) }
buffer.writeUtf(bucket)
}
open fun decode(
buffer: RegistryFriendlyByteBuf,
buckets: List<SpawnBucket>
) {
open fun decode(buffer: RegistryFriendlyByteBuf) {
species = PokemonSpecies.getByIdentifier(buffer.readResourceLocation())!!
spawnablePositionType = buffer.readUtf()
weight = buffer.readFloat()
@@ -116,6 +114,7 @@ sealed class HabitatSpawn {
timeRange = buffer.readNullable { _ -> TimeRange.adapter.deserialize(buffer.readUtf()) }
minLight = buffer.readNullable { _ -> buffer.readInt() }
maxLight = buffer.readNullable { _ -> buffer.readInt() }
bucket = buffer.readUtf()
}
/** Creates the [PokemonSpawnDetail] that will be used in the spawner. This is done per habitat block. */
@@ -138,7 +137,7 @@ sealed class HabitatSpawn {
spawnDetail.apply {
this.id = "habitat_${species.resourceIdentifier}"
this.pokemon = properties
this.bucket = BestSpawner.config.buckets.first { it.weight > 0 }
this.bucket = this@HabitatSpawn.bucket
this.weight = this@HabitatSpawn.weight
this.levelRange = levelRange
this.conditions = mutableListOf(condition)
@@ -1,37 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.habitats
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* A [HabitatPool] of [NaturalHabitatSpawn]s. Mainly just to help with deserialization and ensuring
* a single type for everything that's applied to a habitat block.
*
* @author Hiroku
* @since February 13th, 2026
*/
class NaturalHabitatPool : HabitatPool<NaturalHabitatSpawn>() {
override val type: ResourceLocation = NaturalHabitatSpawn.TYPE
override var spawns: List<NaturalHabitatSpawn> = listOf()
companion object {
fun default() = NaturalHabitatPool().apply {
id = ResourceLocation("cobblemon", "custom__default_natural_pool")
name = "Custom"
}
}
override fun decode(buffer: RegistryFriendlyByteBuf, buckets: List<SpawnBucket>) {
super.decode(buffer, buckets)
spawns = buffer.readList { NaturalHabitatSpawn().apply { decode(buffer, buckets) } }
}
}
@@ -1,63 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.habitats
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.RegistryFriendlyByteBuf
/**
* A type of [HabitatSpawn] that spawns Pokémon as part of natural world spawning, and therefore
* needs to indicate the [SpawnBucket] it will be part of.
*
* @author Hiroku
* @since February 13th, 2026
*/
class NaturalHabitatSpawn : HabitatSpawn() {
companion object {
val TYPE = cobblemonResource("natural")
}
lateinit var bucket: SpawnBucket
override fun createSpawnDetail(habitatBlockEntity: HabitatBlockEntity): PokemonSpawnDetail? {
val spawnDetail = super.createSpawnDetail(habitatBlockEntity)
spawnDetail?.bucket = bucket
return spawnDetail
}
override fun writeToNBT(nbt: CompoundTag) {
super.writeToNBT(nbt)
nbt.putString(DataKeys.HABITAT_POOL_SPAWN_BUCKET, bucket.name)
}
override fun readFromNBT(nbt: CompoundTag) {
super.readFromNBT(nbt)
bucket = Cobblemon.bestSpawner.config.buckets.first { it.name == nbt.getString(DataKeys.HABITAT_POOL_SPAWN_BUCKET) }
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
super.encode(buffer)
buffer.writeUtf(bucket.name)
}
override fun decode(
buffer: RegistryFriendlyByteBuf,
buckets: List<SpawnBucket>
) {
super.decode(buffer, buckets)
val bucketName = buffer.readUtf()
bucket = buckets.first { it.name == bucketName }
}
}
@@ -8,9 +8,7 @@
package com.cobblemon.mod.common.api.habitats.dto
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatPool
import com.cobblemon.mod.common.api.habitats.spawningstyle.ActivatedHabitatSpawning
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import net.minecraft.network.RegistryFriendlyByteBuf
class ActivatedHabitatSettingsDTO() {
@@ -20,7 +18,6 @@ class ActivatedHabitatSettingsDTO() {
var spawnRange = 16
var maxSpawns = -1
var maxSpawnsPerActivation = 1
var habitatPool: HabitatPoolSettingsDTO = HabitatPoolSettingsDTO(ActivatedHabitatPool.default())
constructor(activatedHabitatSpawning: ActivatedHabitatSpawning): this() {
this.chance = activatedHabitatSpawning.chance
@@ -29,7 +26,6 @@ class ActivatedHabitatSettingsDTO() {
this.spawnRange = activatedHabitatSpawning.spawnRange
this.maxSpawns = activatedHabitatSpawning.maxSpawns
this.maxSpawnsPerActivation = activatedHabitatSpawning.maxSpawnsPerActivation
this.habitatPool = HabitatPoolSettingsDTO(activatedHabitatSpawning.pool)
}
fun encode(buffer: RegistryFriendlyByteBuf) {
@@ -39,20 +35,14 @@ class ActivatedHabitatSettingsDTO() {
buffer.writeInt(spawnRange)
buffer.writeInt(maxSpawns)
buffer.writeInt(maxSpawnsPerActivation)
habitatPool.encode(buffer)
}
fun decode(
buffer: RegistryFriendlyByteBuf,
buckets: List<SpawnBucket>
) {
fun decode(buffer: RegistryFriendlyByteBuf) {
this.chance = buffer.readFloat()
this.trigger = buffer.readEnum(ActivatedHabitatSpawning.Trigger::class.java)
this.cancelledNaturalSpawningRange = buffer.readInt()
this.spawnRange = buffer.readInt()
this.maxSpawns = buffer.readInt()
this.maxSpawnsPerActivation = buffer.readInt()
this.habitatPool = HabitatPoolSettingsDTO()
habitatPool.decode(buffer, buckets)
}
}
@@ -9,30 +9,23 @@
package com.cobblemon.mod.common.api.habitats.dto
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatPool
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatSpawn
import com.cobblemon.mod.common.api.habitats.HabitatPool
import com.cobblemon.mod.common.api.habitats.HabitatPools
import com.cobblemon.mod.common.api.habitats.HabitatSpawn
import com.cobblemon.mod.common.api.habitats.NaturalHabitatPool
import com.cobblemon.mod.common.api.habitats.NaturalHabitatSpawn
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
class HabitatPoolSettingsDTO() {
lateinit var id: ResourceLocation
var isReference = false
var isActivated = false
// Below properties are only there when it's not a reference, otherwise the handler will have to look them up from the id
var name: String? = null
var spawns: MutableList<HabitatSpawn>? = null
constructor(habitatPool: HabitatPool<*>): this() {
constructor(habitatPool: HabitatPool): this() {
this.id = habitatPool.id
this.isReference = !id.path.startsWith("custom__")
this.isActivated = habitatPool is ActivatedHabitatPool
if (!this.isReference) {
this.name = habitatPool.name
this.spawns = habitatPool.spawns.toMutableList()
@@ -42,7 +35,6 @@ class HabitatPoolSettingsDTO() {
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(id)
buffer.writeBoolean(isReference)
buffer.writeBoolean(isActivated)
if (!isReference) {
buffer.writeUtf(name!!)
buffer.writeCollection(spawns!!) { _, spawn ->
@@ -52,50 +44,32 @@ class HabitatPoolSettingsDTO() {
}
fun decode(
buffer: RegistryFriendlyByteBuf,
buckets: List<SpawnBucket>
buffer: RegistryFriendlyByteBuf
) {
this.id = buffer.readResourceLocation()
this.isReference = buffer.readBoolean()
this.isActivated = buffer.readBoolean()
if (!isReference) {
this.name = buffer.readUtf()
this.spawns = buffer.readList {
val spawn = if (isActivated) {
ActivatedHabitatSpawn()
} else {
NaturalHabitatSpawn()
}
spawn.decode(buffer, buckets)
val spawn = HabitatSpawn()
spawn.decode(buffer)
spawn
}.toMutableList()
}
}
fun toHabitatPool(): HabitatPool<*>? {
fun toHabitatPool(): HabitatPool? {
if (isReference) {
val pool = HabitatPools.habitatPoolsById[id]
if (pool == null) {
Cobblemon.LOGGER.error("Could not find habitat pool with id $id")
} else if (pool is ActivatedHabitatPool && !isActivated) {
Cobblemon.LOGGER.error("Pool with id $id is an activated habitat pool but was deserialized as a natural pool")
} else if (pool !is ActivatedHabitatPool && isActivated) {
Cobblemon.LOGGER.error("Pool with id $id is a natural habitat pool but was deserialized as an activated pool")
}
return pool
}
return if (isActivated) {
val pool = ActivatedHabitatPool()
pool.id = id
pool.name = name!!
pool.spawns = spawns!!.map { it as ActivatedHabitatSpawn }
pool
} else {
val pool = NaturalHabitatPool()
pool.id = id
pool.name = name!!
pool.spawns = spawns!!.map { it as NaturalHabitatSpawn }
pool
}
val pool = HabitatPool()
pool.id = id
pool.name = name!!
pool.spawns = spawns!!
return pool
}
}
@@ -9,9 +9,9 @@
package com.cobblemon.mod.common.api.habitats.dto
import com.cobblemon.mod.common.api.habitats.HabitatPhaseOrder
import com.cobblemon.mod.common.api.habitats.HabitatPool
import com.cobblemon.mod.common.api.habitats.spawningstyle.ActivatedHabitatSpawning
import com.cobblemon.mod.common.api.habitats.spawningstyle.NaturalHabitatSpawning
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
@@ -23,6 +23,7 @@ class HabitatSettingsDTO() {
var modifiers: String = ""
lateinit var mimicId: ResourceLocation
var isActivatedSpawning = false
var pool: HabitatPoolSettingsDTO = HabitatPoolSettingsDTO(HabitatPool.default())
var activatedSettings: ActivatedHabitatSettingsDTO? = null
var naturalSettings: NaturalHabitatSettingsDTO? = null
@@ -32,6 +33,7 @@ class HabitatSettingsDTO() {
this.levelRange = habitatBlockEntity.levelRange
this.modifiers = habitatBlockEntity.modifiers.asString()
this.mimicId = habitatBlockEntity.mimicId
this.pool = HabitatPoolSettingsDTO(habitatBlockEntity.pool)
val style = habitatBlockEntity.spawningStyle
if (style is ActivatedHabitatSpawning) {
this.isActivatedSpawning = true
@@ -48,6 +50,7 @@ class HabitatSettingsDTO() {
buffer.writeInt(levelRange.last)
buffer.writeUtf(modifiers)
buffer.writeResourceLocation(mimicId)
pool.encode(buffer)
buffer.writeBoolean(isActivatedSpawning)
if (isActivatedSpawning) {
activatedSettings?.encode(buffer)
@@ -56,10 +59,7 @@ class HabitatSettingsDTO() {
}
}
fun decode(
buffer: RegistryFriendlyByteBuf,
buckets: List<SpawnBucket>
) {
fun decode(buffer: RegistryFriendlyByteBuf) {
this.numberOfPhases = buffer.readInt()
this.phaseOrder = buffer.readEnum(HabitatPhaseOrder::class.java)
val levelRangeStart = buffer.readInt()
@@ -67,16 +67,18 @@ class HabitatSettingsDTO() {
this.levelRange = levelRangeStart..levelRangeEnd
this.modifiers = buffer.readUtf()
this.mimicId = buffer.readResourceLocation()
this.pool = HabitatPoolSettingsDTO()
this.pool.decode(buffer)
if (buffer.readBoolean()) {
this.isActivatedSpawning = true
this.naturalSettings = null
val activatedSettings = ActivatedHabitatSettingsDTO()
activatedSettings.decode(buffer, buckets)
activatedSettings.decode(buffer)
this.activatedSettings = activatedSettings
} else {
this.activatedSettings = null
val naturalSettings = NaturalHabitatSettingsDTO()
naturalSettings.decode(buffer, buckets)
naturalSettings.decode(buffer)
this.naturalSettings = naturalSettings
}
}
@@ -8,35 +8,25 @@
package com.cobblemon.mod.common.api.habitats.dto
import com.cobblemon.mod.common.api.habitats.NaturalHabitatPool
import com.cobblemon.mod.common.api.habitats.spawningstyle.NaturalHabitatSpawning
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import net.minecraft.network.RegistryFriendlyByteBuf
class NaturalHabitatSettingsDTO() {
var replaceSpawns = false
var rangeOfInfluence = 16
var habitatPool: HabitatPoolSettingsDTO = HabitatPoolSettingsDTO(NaturalHabitatPool.default())
constructor(naturalHabitatSpawning: NaturalHabitatSpawning): this() {
this.replaceSpawns = naturalHabitatSpawning.replaceSpawns
this.rangeOfInfluence = naturalHabitatSpawning.rangeOfInfluence
this.habitatPool = HabitatPoolSettingsDTO(naturalHabitatSpawning.pool)
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeBoolean(replaceSpawns)
buffer.writeInt(rangeOfInfluence)
habitatPool.encode(buffer)
}
fun decode(
buffer: RegistryFriendlyByteBuf,
buckets: List<SpawnBucket>
) {
fun decode(buffer: RegistryFriendlyByteBuf, ) {
this.replaceSpawns = buffer.readBoolean()
this.rangeOfInfluence = buffer.readInt()
this.habitatPool = HabitatPoolSettingsDTO()
habitatPool.decode(buffer, buckets)
}
}
@@ -8,17 +8,16 @@
package com.cobblemon.mod.common.api.habitats.spawningstyle
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.habitats.HabitatSpawnActivatedEvent
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatPool
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatSpawn
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatSpawningInfluence
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.spawner.FixedAreaSpawner
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
@@ -27,7 +26,7 @@ import net.minecraft.server.level.ServerLevel
* A habitat spawning style defined by being triggered by something. The activation trigger, [trigger], is either
* a redstone pulse, every tick, or every random tick.
*
* The spawn details are generated from the [pool] every time there is some change to the habitat block's settings,
* The spawn details are generated from the pool every time there is some change to the habitat block's settings,
* then those spawn details are used for spawning Pokémon when the habitat block is triggered.
*
* The [chance] property is applied after the trigger logic so that not every activation necessarily results in a spawn
@@ -37,6 +36,10 @@ import net.minecraft.server.level.ServerLevel
* @since February 14th, 2026
*/
class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : HabitatSpawningStyle {
companion object {
val TYPE = cobblemonResource("activated")
}
enum class Trigger {
/** Requires a redstone pulse. */
REDSTONE,
@@ -46,7 +49,8 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
RANDOM_TICK
}
override val type = ActivatedHabitatSpawn.TYPE
@Transient
override val type = TYPE
/** The chance that an activation by the [trigger] will result in a spawn attempt. The spawn attempt may still fail. */
var chance = 1F
@@ -60,11 +64,7 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
var maxSpawns = -1
/** The maximum number of Pokémon that can spawn in a single activation. This will still be capped by [maxSpawns]. */
var maxSpawnsPerActivation = 1
/** The pool of spawns to choose from. */
var pool: ActivatedHabitatPool = ActivatedHabitatPool.default()
// This is cached here so that it doesn't have to be regenerated every time the block is triggered, updated when settings change.
var spawnDetails: List<SpawnDetail> = listOf()
lateinit var spawner: FixedAreaSpawner
override fun writeToNBT(nbt: CompoundTag) {
@@ -75,10 +75,6 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
nbt.putInt(DataKeys.HABITAT_ACTIVATED_SPAWN_RANGE, spawnRange)
nbt.putInt(DataKeys.HABITAT_ACTIVATED_MAX_SPAWNS, maxSpawns)
nbt.putInt(DataKeys.HABITAT_ACTIVATED_MAX_SPAWNS_PER_ACTIVATION, maxSpawnsPerActivation)
val poolNBT = CompoundTag()
writePoolToNBT(pool, poolNBT)
nbt.put(DataKeys.HABITAT_POOL, poolNBT)
}
override fun readFromNBT(nbt: CompoundTag) {
@@ -88,25 +84,18 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
spawnRange = nbt.getInt(DataKeys.HABITAT_ACTIVATED_SPAWN_RANGE)
maxSpawns = nbt.getInt(DataKeys.HABITAT_ACTIVATED_MAX_SPAWNS)
maxSpawnsPerActivation = nbt.getInt(DataKeys.HABITAT_ACTIVATED_MAX_SPAWNS_PER_ACTIVATION)
pool = HabitatSpawningStyle.readPoolFromNBT(
nbt = nbt.getCompound(DataKeys.HABITAT_POOL),
poolInitializer = ::ActivatedHabitatPool,
spawnInitializer = ::ActivatedHabitatSpawn,
defaultPool = ActivatedHabitatPool::default
)
}
fun generateSpawnDetails(world: ServerLevel, pos: BlockPos) {
spawnDetails = pool.createSpawnDetails(habitatBlockEntity)
spawner = FixedAreaSpawner(
name = "habitat_spawner_$pos",
world = world,
position = pos,
spawnPool = SpawnPool("habitat_block").also {
it.details.addAll(spawnDetails)
it.details.addAll(habitatBlockEntity.spawnDetails)
it.precalculate()
},
buckets = Cobblemon.bestSpawner.config.activatedHabitatBuckets,
maxPokemonPerChunk = 16F,
verticalRadius = spawnRange,
horizontalRadius = spawnRange
@@ -118,7 +107,7 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
// Check if the spawn attempt should even happen based on chance.
if (chance < 1F && world.random.nextFloat() >= chance) {
return
} else if (spawnDetails.isEmpty()) {
} else if (habitatBlockEntity.spawnDetails.isEmpty()) {
// If there are no spawn details, then there's no point in trying to spawn anything.
return
}
@@ -8,15 +8,7 @@
package com.cobblemon.mod.common.api.habitats.spawningstyle
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.habitats.HabitatPool
import com.cobblemon.mod.common.api.habitats.HabitatPools
import com.cobblemon.mod.common.api.habitats.HabitatSpawn
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
import net.minecraft.resources.ResourceLocation
/**
@@ -33,47 +25,4 @@ sealed interface HabitatSpawningStyle {
fun writeToNBT(nbt: CompoundTag)
fun readFromNBT(nbt: CompoundTag)
fun writePoolToNBT(pool: HabitatPool<*>, nbt: CompoundTag) {
nbt.putString(DataKeys.HABITAT_POOL_ID, pool.id.toString())
if (pool.id.path.startsWith("custom__")) {
nbt.putString(DataKeys.HABITAT_POOL_NAME, pool.name)
val spawnsListNBT = ListTag()
for (spawn in pool.spawns) {
val spawnTag = CompoundTag()
spawn.writeToNBT(spawnTag)
spawnsListNBT.add(spawnTag)
}
nbt.put(DataKeys.HABITAT_POOL_SPAWNS, spawnsListNBT)
}
}
companion object {
fun <T : HabitatSpawn, P : HabitatPool<T>> readPoolFromNBT(nbt: CompoundTag, poolInitializer: () -> P, spawnInitializer: () -> T, defaultPool: () -> P): P {
var pool: P
val poolId = nbt.getString(DataKeys.HABITAT_POOL_ID).asIdentifierDefaultingNamespace()
if (nbt.contains(DataKeys.HABITAT_POOL_NAME)) {
// It's one that was stored on the block
pool = poolInitializer()
pool.id = poolId
pool.name = nbt.getString(DataKeys.HABITAT_POOL_NAME)
val spawnsListNBT = nbt.getList(DataKeys.HABITAT_POOL_SPAWNS, Tag.TAG_COMPOUND.toInt())
val spawns = mutableListOf<T>()
spawnsListNBT.forEach { spawnTag ->
try {
val spawn = spawnInitializer().apply { readFromNBT(spawnTag as CompoundTag) }
spawns.add(spawn)
} catch (_: Exception) {
// If there's an error reading a spawn, skip it and log the error.
Cobblemon.LOGGER.error("Error reading activated habitat spawn from NBT for habitat block, skipping.")
}
}
pool.spawns = spawns
} else {
pool = HabitatPools.habitatPoolsById[poolId] as? P ?: defaultPool()
}
return pool
}
}
}
@@ -8,21 +8,18 @@
package com.cobblemon.mod.common.api.habitats.spawningstyle
import com.cobblemon.mod.common.api.habitats.NaturalHabitatPool
import com.cobblemon.mod.common.api.habitats.NaturalHabitatSpawn
import com.cobblemon.mod.common.api.habitats.spawningstyle.HabitatSpawningStyle.Companion.readPoolFromNBT
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.nbt.CompoundTag
import net.minecraft.resources.ResourceLocation
/**
* A habitat spawning style defined by tapping into regular spawning methods. This works by adding to the spawn list
* for spawning that's occurring nearby. When [replaceSpawns] is set to true, the original spawns will be
* removed completely in favour of the spawns provided in this habitat's [pool].
* removed completely in favour of the spawns provided in this habitat's pool.
*
* The spawn details are generated from the [pool] every time there is some change to the habitat block's settings,
* The spawn details are generated from the pool every time there is some change to the habitat block's settings,
* then those spawn details are used for spawning Pokémon when world spawning is occurring nearby.
*
* Whether or not this interactions with overworld or fishing spawns is determined by whether the habitat pool has
@@ -32,10 +29,13 @@ import net.minecraft.resources.ResourceLocation
* @since February 22nd, 2026
*/
class NaturalHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : HabitatSpawningStyle {
companion object {
val TYPE = cobblemonResource("natural")
}
@Transient
override val type: ResourceLocation = NaturalHabitatSpawn.TYPE
override val type: ResourceLocation = TYPE
var pool: NaturalHabitatPool = NaturalHabitatPool.default()
var replaceSpawns = false
var rangeOfInfluence = 16
@@ -43,33 +43,19 @@ class NaturalHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Habit
var affectsFishing = false
@Transient
var affectsOverworld = false
@Transient
var spawnDetails: List<SpawnDetail> = listOf()
fun generateSpawnDetails() {
spawnDetails = pool.createSpawnDetails(habitatBlockEntity = habitatBlockEntity)
affectsFishing = spawnDetails.any { it.spawnablePositionType.name == "fishing" }
affectsOverworld = spawnDetails.any { it.spawnablePositionType.name != "fishing" }
affectsFishing = habitatBlockEntity.spawnDetails.any { it.spawnablePositionType.name == "fishing" }
affectsOverworld = habitatBlockEntity.spawnDetails.any { it.spawnablePositionType.name != "fishing" }
}
override fun writeToNBT(nbt: CompoundTag) {
nbt.putBoolean(DataKeys.HABITAT_NATURAL_REPLACE_SPAWNS, replaceSpawns)
nbt.putInt(DataKeys.HABITAT_NATURAL_RANGE_OF_INFLUENCE, rangeOfInfluence)
val poolNBT = CompoundTag()
writePoolToNBT(pool, poolNBT)
nbt.put(DataKeys.HABITAT_POOL, poolNBT)
}
override fun readFromNBT(nbt: CompoundTag) {
replaceSpawns = nbt.getBoolean(DataKeys.HABITAT_NATURAL_REPLACE_SPAWNS)
rangeOfInfluence = nbt.getInt(DataKeys.HABITAT_NATURAL_RANGE_OF_INFLUENCE)
pool = readPoolFromNBT(
nbt = nbt.getCompound(DataKeys.HABITAT_POOL),
poolInitializer = ::NaturalHabitatPool,
spawnInitializer = ::NaturalHabitatSpawn,
defaultPool = NaturalHabitatPool::default
)
}
}
@@ -51,11 +51,15 @@ data class PokemonInteractionSet(
}
data class PokemonInteraction(
val grouping: ResourceLocation,
val requirements: List<Requirement> = listOf(),
val effects: List<InteractionEffect> = listOf(),
val cooldown: ExpressionLike = "0".asExpressionLike()
) {
// Not put as a necessary constructor parameter because then there isn't a default constructor
// and that means Gson just gives null for everything in the constructor and falls back to the JSON
// properties - completely ignoring the default values above.
lateinit var grouping: ResourceLocation
fun encode(buffer: FriendlyByteBuf) {
buffer.writeResourceLocation(grouping)
buffer.writeCollection(requirements) { it, requirement ->
@@ -76,11 +80,12 @@ data class PokemonInteraction(
val cooldown = buffer.readExpressionLike()
return PokemonInteraction(
grouping,
requirements,
effects,
cooldown,
)
).also {
it.grouping = grouping
}
}
}
}
@@ -38,7 +38,7 @@ import net.minecraft.world.phys.AABB
* @since July 29th, 2023
*/
interface PokemonSelectingItem {
fun use(player: ServerPlayer, stack: ItemStack): InteractionResultHolder<ItemStack> {
fun use(player: ServerPlayer, stack: ItemStack, ignoreShift: Boolean = false): InteractionResultHolder<ItemStack> {
val range = player.entityInteractionRange()
val entity = player.level()
.getEntities(player, AABB.ofSize(player.position(), range, range, range))
@@ -60,7 +60,7 @@ interface PokemonSelectingItem {
return interactWithSpecificBattle(player, stack, battlePokemon)
}
} ?: run {
if (!player.isShiftKeyDown) {
if (ignoreShift || !player.isShiftKeyDown) {
return if (entity != null) {
val pokemon = entity.pokemon
if (entity.ownerUUID == player.uuid) {
@@ -109,7 +109,7 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
DoubleValue(pokemon.species.nationalPokedexNumber.toDouble())
}
map["types"] = {
pokemon.form.types.map { it.toString() }.asArrayValue(::StringValue)
pokemon.form.types.map { it.showdownId }.asArrayValue(::StringValue)
}
map["gender_ratio"] = {
DoubleValue(pokemon.form.maleRatio.toDouble())
@@ -72,6 +72,40 @@ abstract class AbstractPokedexManager {
} ?: PokedexEntryProgress.UNREGISTERED
}
fun getHighestKnowledgeFor(entry: PokedexEntry, form: PokedexForm?): PokedexEntryProgress {
if (form == null) return getHighestKnowledgeFor(entry)
val speciesRecord = getSpeciesRecord(entry.speciesId) ?: return PokedexEntryProgress.UNREGISTERED
val hasAllAspects = entry.conditionAspects.all(speciesRecord::hasAspect)
if (!hasAllAspects) {
return PokedexEntryProgress.UNREGISTERED
}
return speciesRecord.getFormRecord(form.displayForm)?.knowledge ?: PokedexEntryProgress.UNREGISTERED
}
fun getHighestKnowledgeFor(entry: PokedexEntry, form: PokedexForm?, aspects: Iterable<String>): PokedexEntryProgress {
val formKnowledge = getHighestKnowledgeFor(entry, form)
if (formKnowledge == PokedexEntryProgress.UNREGISTERED) return PokedexEntryProgress.UNREGISTERED
val seenAspects = getSeenAspects(entry)
val allSeenAspects = aspects
// TODO this is ugly
.filter { it ->
if (Dexes.equivalentFormsLookup[it] != null) return@filter false
if (it.uppercase() in setOf(Gender.MALE.name, Gender.FEMALE.name, Gender.GENDERLESS.name)) return@filter false
if ("shiny".equals(it, ignoreCase = true)) return@filter false
return@filter true
}
.all { it -> seenAspects.contains(it) }
if (!allSeenAspects) return PokedexEntryProgress.UNREGISTERED
return formKnowledge
}
fun getEncounteredForms(entry: PokedexEntry) : List<PokedexForm> {
return getFormsWithKnowledge(entry, PokedexEntryProgress.SEEN)
}
@@ -10,6 +10,9 @@ package com.cobblemon.mod.common.api.pokedex
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokedex.def.PokedexDef
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.PokedexDexSyncPacket
import com.cobblemon.mod.common.util.adapters.CodecBackedAdapter
@@ -40,6 +43,17 @@ object Dexes : JsonDataRegistry<PokedexDef> {
//Maps a dex id to its PokedexDef
val dexEntryMap = linkedMapOf<ResourceLocation, PokedexDef>()
val equivalentForms = mapOf(
"galar" to listOf("region-bias-galar", "bias-galar", "galar-bias", "galarian", "galar"),
"alola" to listOf("region-bias-alola", "bias-alola", "alola-bias", "alolan", "alola"),
"hisui" to listOf("region-bias-hisui", "bias-hisui", "hisui-bias", "hisuian", "hisui"),
"paldea" to listOf("region-bias-paldea", "bias-paldea", "paldea-bias", "paldean", "paldea"),
)
val equivalentFormsLookup = equivalentForms.flatMap { (key, values) ->
values.map { it to key }
}.toMap()
override fun reload(data: Map<ResourceLocation, PokedexDef>) {
dexEntryMap.clear()
data.entries.sortedBy { it.value.sortOrder }.forEach { (id, def) -> dexEntryMap[id] = def }
@@ -49,4 +63,34 @@ object Dexes : JsonDataRegistry<PokedexDef> {
override fun sync(player: ServerPlayer) {
PokedexDexSyncPacket(dexEntryMap.values).sendToPlayer(player)
}
fun findDexEntryBySpeciesId(regionId: ResourceLocation, speciesId: ResourceLocation): PokedexEntry? {
return dexEntryMap[regionId]?.getEntries()?.firstOrNull { it -> it.speciesId == speciesId }
}
fun findDexEntryBySpeciesId(speciesId: ResourceLocation): PokedexEntry? {
return findDexEntryBySpeciesId(cobblemonResource("national"), speciesId)
}
fun findRootDexEntryBySpeciesId(speciesId: ResourceLocation, formName: String): Pair<PokedexEntry, PokedexForm> {
var rootSpecies = speciesId.let { PokemonSpecies.getByIdentifier(it) }!!
while (rootSpecies.preEvolution != null) {
rootSpecies = rootSpecies.preEvolution!!.species
}
val entry = findDexEntryBySpeciesId(rootSpecies.resourceIdentifier)
?: throw RuntimeException("Root dex entry not found")
val formEquivalents = getFormEquivalents(formName)
val form =
entry.forms.firstOrNull { formEquivalents.contains(it.displayForm.lowercase()) } ?:
entry.forms.first { it.displayForm.equals("Normal", ignoreCase = true) }
return entry to form
}
fun getFormEquivalents(formName: String): List<String> {
val key = equivalentFormsLookup[formName.lowercase()]
return equivalentForms[key] ?: listOf(formName.lowercase())
}
}
@@ -56,10 +56,8 @@ class AggregatePokedexDef(
return speciesToEntry.values.toList()
}
}
override fun shouldSynchronize(other: PokedexDef) = true
override fun decode(buffer: RegistryFriendlyByteBuf) {
fun decode(buffer: RegistryFriendlyByteBuf) {
sortOrder = buffer.readSizedInt(IntSize.U_BYTE)
val size = buffer.readInt()
for (i in 0 until size) {
@@ -67,7 +65,7 @@ class AggregatePokedexDef(
}
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeSizedInt(IntSize.U_BYTE, sortOrder)
buffer.writeInt(subDexIds.size)
subDexIds.forEach {
@@ -8,8 +8,6 @@
package com.cobblemon.mod.common.api.pokedex.def
import com.cobblemon.mod.common.api.data.ClientDataSynchronizer
import com.cobblemon.mod.common.api.pokedex.entry.DexEntries
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec
@@ -23,7 +21,7 @@ import net.minecraft.resources.ResourceLocation
* @since August 24, 2024
* @author Apion
*/
abstract class PokedexDef: ClientDataSynchronizer<PokedexDef> {
abstract class PokedexDef {
//The ID used to find the codecs for this "type" of PokedexDef
abstract val typeId: ResourceLocation
//The ID of this dex in the Dexes registry
@@ -45,9 +45,7 @@ class SimplePokedexDef(
override fun getEntries() = entries.mapNotNull { DexEntries.entries[it] }
override fun shouldSynchronize(other: PokedexDef) = true
override fun decode(buffer: RegistryFriendlyByteBuf) {
fun decode(buffer: RegistryFriendlyByteBuf) {
sortOrder = buffer.readSizedInt(IntSize.U_BYTE)
val size = buffer.readInt()
for (i in 0 until size) {
@@ -55,7 +53,7 @@ class SimplePokedexDef(
}
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeSizedInt(IntSize.U_BYTE, sortOrder)
buffer.writeInt(entries.size)
entries.forEach {
@@ -41,16 +41,18 @@ class PokedexCategoryFilter(
PokedexCategoryFilterType.UNDISCOVERED_TM_MOVE -> hasUndiscoveredLevelUpTM(entry)
PokedexCategoryFilterType.RIDEABLE -> {
val species = PokemonSpecies.getByIdentifier(entry.speciesId)
species?.forms?.any { form -> !form.riding.behaviours.isNullOrEmpty() } == true
&& pokedexManager.getHighestKnowledgeFor(entry) >= PokedexEntryProgress.OWNED
// we were silly as standard forms also can be rideable and we were ingoring those
(species?.forms.orEmpty() + listOfNotNull(species?.standardForm)).any { form -> !form.riding.behaviours.isNullOrEmpty() }
&& (pokedexManager.getHighestKnowledgeFor(entry) >= PokedexEntryProgress.OWNED ||
pokedexManager.getHighestKnowledgeFor(entry) >= PokedexEntryProgress.SEEN)
}
}
}
private fun hasUndiscoveredLevelUpTM(entry: PokedexEntry): Boolean {
if (pokedexManager.getHighestKnowledgeFor(entry) != PokedexEntryProgress.OWNED) return false
if (pokedexManager.getHighestKnowledgeFor(entry) == PokedexEntryProgress.UNREGISTERED) return false
val species = PokemonSpecies.getByIdentifier(entry.speciesId) ?: return false
val forms = pokedexManager.getCaughtForms(entry)
val forms = pokedexManager.getEncounteredForms(entry)
val formData = if (forms.isEmpty()) {
listOf(species.standardForm)
} else {
@@ -72,7 +72,7 @@ class SearchFilter(val pokedexManager: AbstractPokedexManager, val searchString:
}
}
SearchByType.DROPS -> {
if (pokedexManager.getHighestKnowledgeFor(entry) !== PokedexEntryProgress.OWNED) return false
if (pokedexManager.getHighestKnowledgeFor(entry) == PokedexEntryProgress.UNREGISTERED) return false
val dropsList = mutableListOf<String>()
val formsList = if (species.forms.isEmpty()) mutableListOf(species.standardForm) else species.forms
formsList.forEach {
@@ -131,9 +131,7 @@ class SearchFilter(val pokedexManager: AbstractPokedexManager, val searchString:
form.moves.tutorMoves,
form.moves.eggMoves,
form.moves.evolutionMoves,
form.moves.formChangeMoves,
form.moves.specialMoves,
form.moves.legacyMoves
form.moves.formChangeMoves
)
for (moves in alwaysDiscovered) {
@@ -674,9 +674,6 @@ open class PokemonProperties {
@JvmOverloads
fun createEntity(world: Level, player: ServerPlayer? = null): PokemonEntity {
val pokemon = create(player)
if (pokemon.isAlpha) {
pokemon.initializeMovesetWithRandomTm()
}
return PokemonEntity(world, pokemon).also { applyCustomProperties(it) }
}
@@ -0,0 +1,30 @@
/*
* 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.pokemon.evolution
import com.cobblemon.mod.common.pokemon.evolution.variants.*
interface EvolutionVisitor<R> {
fun visit(evolution: Evolution): R? {
return when (evolution) {
is BlockClickEvolution -> visitBlockClickEvolution(evolution)
is DummyEvolution -> visitDummyEvolution(evolution)
is ItemInteractionEvolution -> visitItemInteractionEvolution(evolution)
is LevelUpEvolution -> visitLevelUpEvolution(evolution)
is TradeEvolution -> visitTradeEvolution(evolution)
else -> null
}
}
fun visitBlockClickEvolution(blockClickEvolution: BlockClickEvolution): R
fun visitDummyEvolution(evolution: Evolution): R // TODO: Use dummyEvolution?
fun visitItemInteractionEvolution(itemInteractionEvolution: ItemInteractionEvolution): R
fun visitLevelUpEvolution(levelUpEvolution: LevelUpEvolution): R
fun visitTradeEvolution(tradeEvolution: TradeEvolution): R
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.pokemon.moves
import com.cobblemon.mod.common.api.data.ClientDataSynchronizer
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.net.IntSize
@@ -18,7 +17,7 @@ import com.cobblemon.mod.common.util.writeSizedInt
import com.google.gson.JsonElement
import net.minecraft.network.RegistryFriendlyByteBuf
open class Learnset : ClientDataSynchronizer<Learnset> {
open class Learnset {
class Interpreter(val loadMove: (JsonElement, Learnset) -> Boolean) {
companion object {
fun parseFromPrefixIntoList(prefix: String, list: (Learnset) -> MutableList<MoveTemplate>): Interpreter {
@@ -111,9 +110,9 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
}
// We only sync level up moves atm
override fun shouldSynchronize(other: Learnset) = other.levelUpMoves != this.levelUpMoves
fun shouldSynchronize(other: Learnset) = other.levelUpMoves != this.levelUpMoves
override fun decode(buffer: RegistryFriendlyByteBuf) {
fun decode(buffer: RegistryFriendlyByteBuf) {
this.levelUpMoves.clear()
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
val level = buffer.readSizedInt(IntSize.U_SHORT)
@@ -125,7 +124,7 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
}
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeSizedInt(IntSize.U_BYTE, levelUpMoves.size)
for ((level, moves) in levelUpMoves) {
buffer.writeSizedInt(IntSize.U_SHORT, level)
@@ -21,7 +21,7 @@ import net.minecraft.world.entity.LivingEntity
* @author Licious
* @since March 21st, 2022
*/
interface EntityQueryRequirement : Requirement {
abstract class EntityQueryRequirement : Requirement() {
override fun check(pokemon: Pokemon): Boolean {
val queriedEntity = pokemon.entity ?: pokemon.getOwnerPlayer() ?: return false
return this.check(pokemon, queriedEntity)
@@ -34,5 +34,5 @@ interface EntityQueryRequirement : Requirement {
* @param queriedEntity The [LivingEntity] that can be compared in context of a [Level].
* @return If the requirement was satisfied.
*/
fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
abstract fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
}
@@ -23,7 +23,7 @@ import net.minecraft.world.entity.player.Player
* @author Polymeta
* @since May 6th, 2025
*/
interface OwnerQueryRequirement : Requirement {
abstract class OwnerQueryRequirement : Requirement() {
override fun check(pokemon: Pokemon): Boolean {
val owner = pokemon.getOwnerEntity() ?: return false
return when (owner) {
@@ -44,7 +44,7 @@ interface OwnerQueryRequirement : Requirement {
* @param owner The [Player] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
abstract fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
/**
* Checks if the given [Pokemon] & [NPCEntity] satisfies the requirement.
@@ -55,5 +55,5 @@ interface OwnerQueryRequirement : Requirement {
* @param owner The [NPCEntity] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
abstract fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.pokemon.requirement
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.resources.ResourceLocation
/**
* Represents a universal requirement suitable for various checks on pokemon..
@@ -22,7 +23,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 19th, 2022
*/
fun interface Requirement {
abstract class Requirement {
/**
* Checks if the given [Pokemon] satisfies the requirement.
@@ -30,6 +31,8 @@ fun interface Requirement {
* @param pokemon The [Pokemon] being queried.
* @return If the requirement was satisfied.
*/
fun check(pokemon: Pokemon): Boolean
abstract fun check(pokemon: Pokemon): Boolean
val pokedexIcon: ResourceLocation? = null
val pokedexTooltip: String? = null
}
@@ -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.pokemon.requirement
import com.cobblemon.mod.common.pokemon.requirements.*
interface RequirementVisitor<R> {
fun visit(requirement: Requirement): R? {
return when (requirement) {
is AdvancementRequirement -> visitAdvancementRequirement(requirement)
is AnyRequirement -> visitAnyRequirement(requirement)
is AreaRequirement -> visitAreaRequirement(requirement)
is AttackDefenceRatioRequirement -> visitAttackDefenceRatioRequirement(requirement)
is BattleCriticalHitsRequirement -> visitBattleCriticalHitsRequirement(requirement)
is BiomeRequirement -> visitBiomeRequirement(requirement)
is BlocksTraveledRequirement -> visitBlocksTraveledRequirement(requirement)
is DamageTakenRequirement -> visitDamageTakenRequirement(requirement)
is DefeatRequirement -> visitDefeatRequirement(requirement)
is FriendshipRequirement -> visitFriendshipRequirement(requirement)
is HeldItemRequirement -> visitHeldItemRequirement(requirement)
is LevelRequirement -> visitLevelRequirement(requirement)
is MoonPhaseRequirement -> visitMoonPhaseRequirement(requirement)
is MoveSetRequirement -> visitMoveSetRequirement(requirement)
is MoveTypeRequirement -> visitMoveTypeRequirement(requirement)
is OwnerHoldsItemRequirement -> visitOwnerHoldsItemRequirement(requirement)
is PartyMemberRequirement -> visitPartyMemberRequirement(requirement)
is PokemonPropertiesRequirement -> visitPokemonPropertiesRequirement(requirement)
is PropertyRangeRequirement -> visitPropertyRangeRequirement(requirement)
is RecoilRequirement -> visitRecoilRequirement(requirement)
is StatCompareRequirement -> visitStatCompareRequirement(requirement)
is StatEqualRequirement -> visitStatEqualRequirement(requirement)
is StructureRequirement -> visitStructureRequirement(requirement)
is TimeRangeRequirement -> visitTimeRangeRequirement(requirement)
is UseMoveRequirement -> visitUseMoveRequirement(requirement)
is WeatherRequirement -> visitWeatherRequirement(requirement)
is WorldRequirement -> visitWorldRequirement(requirement)
else -> null
}
}
fun visitAdvancementRequirement(advancementRequirement: AdvancementRequirement): R
fun visitAnyRequirement(anyRequirement: AnyRequirement): R
fun visitAreaRequirement(areaRequirement: AreaRequirement): R
fun visitAttackDefenceRatioRequirement(attackDefenceRatioRequirement: AttackDefenceRatioRequirement): R
fun visitBattleCriticalHitsRequirement(battleCriticalHitsRequirement: BattleCriticalHitsRequirement): R
fun visitBiomeRequirement(biomeRequirement: BiomeRequirement): R
fun visitBlocksTraveledRequirement(blocksTraveledRequirement: BlocksTraveledRequirement): R
fun visitDamageTakenRequirement(damageTakenRequirement: DamageTakenRequirement): R
fun visitDefeatRequirement(defeatRequirement: DefeatRequirement): R
fun visitFriendshipRequirement(friendshipRequirement: FriendshipRequirement): R
fun visitHeldItemRequirement(heldItemRequirement: HeldItemRequirement): R
fun visitLevelRequirement(levelRequirement: LevelRequirement): R
fun visitMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): R
fun visitMoveSetRequirement(moveSetRequirement: MoveSetRequirement): R
fun visitMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): R
fun visitOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): R
fun visitPartyMemberRequirement(partyMemberRequirement: PartyMemberRequirement): R
fun visitPokemonPropertiesRequirement(pokemonPropertiesRequirement: PokemonPropertiesRequirement): R
fun visitPropertyRangeRequirement(propertyRangeRequirement: PropertyRangeRequirement): R
fun visitRecoilRequirement(recoilRequirement: RecoilRequirement): R
fun visitStatCompareRequirement(statCompareRequirement: StatCompareRequirement): R
fun visitStatEqualRequirement(statEqualRequirement: StatEqualRequirement): R
fun visitStructureRequirement(structureRequirement: StructureRequirement): R
fun visitTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): R
fun visitUseMoveRequirement(useMoveRequirement: UseMoveRequirement): R
fun visitWeatherRequirement(weatherRequirement: WeatherRequirement): R
fun visitWorldRequirement(worldRequirement: WorldRequirement): R
}
@@ -22,8 +22,8 @@ import net.minecraft.network.RegistryFriendlyByteBuf
*/
data class Seat(
val locator: String = "",
val condition: Expression?,
val poseAnimations: MutableList<SeatPoseAnimations>?,
val condition: Expression? = null,
val poseAnimations: MutableList<SeatPoseAnimations>? = null,
val handsBusy: Boolean = false,
) : Encodable {
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.snowstorm
import com.cobblemon.mod.common.client.render.shader.CobblemonShaders
import com.mojang.blaze3d.platform.GlStateManager
import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.BufferBuilder
@@ -16,6 +15,7 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat
import com.mojang.blaze3d.vertex.Tesselator
import com.mojang.blaze3d.vertex.VertexFormat
import net.minecraft.client.particle.ParticleRenderType
import net.minecraft.client.renderer.GameRenderer
import net.minecraft.client.renderer.texture.TextureAtlas
import net.minecraft.client.renderer.texture.TextureManager
@@ -23,8 +23,9 @@ object ParticleMaterials {
val ALPHA = object : ParticleRenderType {
override fun begin(tessellator: Tesselator, textureManager: TextureManager): BufferBuilder {
RenderSystem.enableBlend()
RenderSystem.enableCull()
RenderSystem.depthMask(true)
RenderSystem.setShader { CobblemonShaders.PARTICLE_CUTOUT }
RenderSystem.setShader { GameRenderer.getParticleShader() }
RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES)
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA)
return tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE)
@@ -36,10 +37,11 @@ object ParticleMaterials {
val ADD = object : ParticleRenderType {
override fun begin(tessellator: Tesselator, textureManager: TextureManager): BufferBuilder {
RenderSystem.enableBlend()
RenderSystem.disableCull()
RenderSystem.depthMask(true)
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
RenderSystem.setShader { GameRenderer.getParticleShader() }
RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES)
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA)
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE)
return tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE)
}
@@ -49,10 +51,11 @@ object ParticleMaterials {
val BLEND = object : ParticleRenderType {
override fun begin(tessellator: Tesselator, textureManager: TextureManager): BufferBuilder {
RenderSystem.enableBlend()
RenderSystem.disableCull()
RenderSystem.depthMask(true)
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
RenderSystem.setShader { GameRenderer.getParticleShader() }
RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES)
RenderSystem.blendFunc(GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.ZERO)
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA)
return tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE)
}
@@ -62,10 +65,11 @@ object ParticleMaterials {
val OPAQUE = object : ParticleRenderType {
override fun begin(tessellator: Tesselator, textureManager: TextureManager): BufferBuilder {
RenderSystem.enableBlend()
RenderSystem.enableCull()
RenderSystem.depthMask(true)
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
RenderSystem.setShader { GameRenderer.getParticleShader() }
RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES)
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE)
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_COLOR, GlStateManager.DestFactor.ZERO)
return tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE)
}
@@ -18,12 +18,12 @@ import com.cobblemon.mod.common.api.spawning.condition.SeafloorSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SubmergedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SurfaceSpawningCondition
import com.cobblemon.mod.common.api.spawning.detail.EmptySpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.NPCSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.PokemonHerdSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
import com.cobblemon.mod.common.api.spawning.position.FishingSpawnablePosition
@@ -121,6 +121,7 @@ object BestSpawner {
SpawnDetail.registerSpawnType(name = PokemonSpawnDetail.TYPE, PokemonSpawnDetail::class.java)
SpawnDetail.registerSpawnType(name = NPCSpawnDetail.TYPE, NPCSpawnDetail::class.java)
SpawnDetail.registerSpawnType(name = PokemonHerdSpawnDetail.TYPE, PokemonHerdSpawnDetail::class.java)
SpawnDetail.registerSpawnType(name = EmptySpawnDetail.TYPE, EmptySpawnDetail::class.java)
LOGGER.info("Loaded ${SpawnDetail.spawnDetailTypes.size} spawn detail types.")
loadConfig()
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning
/**
* A spawn bucket is a simple referenceable object by spawn files. The bucket is used at the beginning of
* the selection process to decide which set of spawns will be used for spawning on that attempt. Weights are used to
* make entire buckets more or less likely, and then weighted selections will occur within whichever bucket
* was chosen.
*
* Spawn buckets are configured in the main config.
*
* @author Hiroku
* @since June 20th, 2022
*/
class SpawnBucket() {
lateinit var name: String
var weight = 0F
constructor(name: String, weight: Float): this() {
this.name = name
this.weight = weight
}
override fun hashCode() = name.hashCode()
override fun equals(other: Any?) = other is SpawnBucket && other.name == name
}
@@ -49,7 +49,6 @@ object SpawnDetailPresets : JsonDataRegistry<SpawnDetailPreset> {
.setPrettyPrinting()
.setLenient()
.disableHtmlEscaping()
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
.registerTypeAdapter(SpawnablePositionType::class.java, RegisteredSpawnablePositionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
@@ -67,7 +67,6 @@ object SpawnLoader {
.registerTypeAdapter(MoonPhaseRange::class.java, IntRangesAdapter(MoonPhaseRange.moonPhaseRanges) { MoonPhaseRange(*it) })
.registerTypeAdapter(ItemDropMethod::class.java, ItemDropMethod.adapter)
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
.registerTypeAdapter(CompoundTag::class.java, NbtCompoundAdapter)
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
.registerTypeAdapter(PossibleHeldItem::class.java, PossibleHeldItemAdapter)
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.api.spawning.TimeRange.Companion.timeRanges
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.MutableComponent
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
/**
@@ -49,4 +51,25 @@ class TimeRange : IntRanges {
constructor() : super()
constructor(vararg ranges: IntRange) : super(*ranges)
fun displayName(): MutableComponent? {
val key = timeRanges.entries.firstOrNull { entry -> this == entry.value }?.key ?: return null
return lang("ui.time_range.$key")
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TimeRange) return false
if (other.ranges.size != this.ranges.size) return false
other.ranges.forEachIndexed { index, otherRange ->
if (this.ranges[index] != otherRange) return false
}
return true
}
override fun hashCode(): Int {
return ranges.hashCode()
}
}
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.MutableComponent
import net.minecraft.world.level.Level
/**
@@ -42,4 +44,7 @@ enum class MoonPhase {
fun ofWorld(world: Level): MoonPhase = VALUES[world.moonPhase]
}
fun displayName(): MutableComponent {
return lang("ui.moon_phase.${this.name.lowercase()}")
}
}
@@ -8,10 +8,9 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import net.minecraft.resources.ResourceLocation
/**
@@ -22,8 +21,8 @@ import net.minecraft.resources.ResourceLocation
* time as sharing that value. The requirement of implementations is only to get that
* key from both a [SpawnDetail] and a [SpawnablePosition].
*
* When a precalculation has been registered with a [Spawner] by adding to [Spawner.precalculators],
* the precalculation result will need to be updated by running [Spawner.precalculate]. That
* When a precalculation has been registered with a [SpawnPool] by adding to [SpawnPool.precalculators],
* the precalculation result will need to be updated by running [SpawnPool.precalculate]. That
* might take it a hot minute, but the result will be that there is an extra layer of
* shortcutting to the matching algorithm.
*
@@ -34,7 +33,7 @@ interface SpawningPrecalculation<T : Any> {
/** Retrieves the precalculation keys for the given spawn detail. */
fun select(detail: SpawnDetail): Collection<T>
/** Retrieves the precalculation key for the given spawnable position, if that key exists for this position. */
fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): T?
fun select(bucket: String, spawnablePosition: SpawnablePosition): T?
/**
* Generates a precalculation result for the list of [SpawnDetail]s and the subsequent precalculations.
@@ -74,7 +73,7 @@ interface SpawningPrecalculation<T : Any> {
object RootPrecalculation : SpawningPrecalculation<Any> {
val list = listOf(Unit)
override fun select(detail: SpawnDetail): List<Any> = list
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): Any = Unit
override fun select(bucket: String, spawnablePosition: SpawnablePosition): Any = Unit
}
/**
@@ -85,12 +84,12 @@ object RootPrecalculation : SpawningPrecalculation<Any> {
*/
object SpawnablePositionTypePrecalculation : SpawningPrecalculation<Class<out SpawnablePosition>> {
override fun select(detail: SpawnDetail) = listOf(detail.spawnablePositionType.clazz)
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = spawnablePosition::class.java
override fun select(bucket: String, spawnablePosition: SpawnablePosition) = spawnablePosition::class.java
}
object BucketPrecalculation : SpawningPrecalculation<SpawnBucket> {
object BucketPrecalculation : SpawningPrecalculation<String> {
override fun select(detail: SpawnDetail) = listOf(detail.bucket)
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = bucket
override fun select(bucket: String, spawnablePosition: SpawnablePosition) = bucket
}
/**
@@ -99,7 +98,7 @@ object BucketPrecalculation : SpawningPrecalculation<SpawnBucket> {
*/
object BiomePrecalculation : SpawningPrecalculation<ResourceLocation> {
override fun select(detail: SpawnDetail) = detail.validBiomes
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = spawnablePosition.biomeHolder.unwrapKey().map { it.location() }.orElse(null)
override fun select(bucket: String, spawnablePosition: SpawnablePosition) = spawnablePosition.biomeHolder.unwrapKey().map { it.location() }.orElse(null)
}
/**
@@ -114,7 +113,7 @@ sealed class PrecalculationResult<T : Any>(
val calculation: SpawningPrecalculation<*>
) {
/** Gets the list of spawn details that fit this spawnable position. */
abstract fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail>
abstract fun retrieve(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail>
}
/**
@@ -127,7 +126,7 @@ class NestedPrecalculationResult<T : Any>(
calculation: SpawningPrecalculation<T>,
val mapping: Map<T, PrecalculationResult<*>> = mutableMapOf()
) : PrecalculationResult<T>(calculation) {
override fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)]?.retrieve(bucket, spawnablePosition) ?: emptyList()
override fun retrieve(bucket: String, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)]?.retrieve(bucket, spawnablePosition) ?: emptyList()
}
/**
@@ -141,5 +140,5 @@ class FinalPrecalculationResult<T : Any>(
calculation: SpawningPrecalculation<*>,
val mapping: Map<T, List<SpawnDetail>>
) : PrecalculationResult<T>(calculation) {
override fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)] ?: emptyList()
override fun retrieve(bucket: String, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)] ?: emptyList()
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
/**
* Does a whole lot of nothing. Spawns nothing.
*
* @author Hiroku
* @since May 16th, 2026
*/
class EmptySpawnAction(
spawnablePosition: SpawnablePosition,
bucket: String,
detail: EmptySpawnDetail
) : SpawnAction<Unit>(spawnablePosition, bucket, detail) {
override fun run() {}
}
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
/**
* A spawn detail for nothing. It is used to take a slot, like to weigh down a spawn attempt,
* with something that ultimately doesn't spawn anything.
*
* The use case for this is very niche. With 1.8, the buckets that can be selected by a spawner
* during a spawn attempt will be narrowed down to the buckets that are used by the spawn
* pool. That means that if a bucket is never used by the pool, it will never be selected. That
* way, a bucket won't be selected when it never had any chance of being selected. This is what
* you would want in almost every case.
*
* However, in some cases you may want spawning to not spawn anything or you may want to preserve
* the relative rarity of the other buckets, and in that case you'd put something like this in a
* bucket so that it technically exists in the spawn pool without actually resulting in a spawned
* entity.
*
* @author Hiroku
* @since May 16th, 2026
*/
class EmptySpawnDetail : SpawnDetail() {
companion object {
val TYPE = "empty"
}
override val type: String = TYPE
override fun createSpawnAction(
spawnablePosition: SpawnablePosition,
bucket: String,
selectionData: SpawnSelectionData
) = EmptySpawnAction(
spawnablePosition = spawnablePosition,
bucket = bucket,
detail = this
)
}
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.util.resolveInt
@@ -20,7 +19,7 @@ import com.cobblemon.mod.common.util.resolveInt
* @author Hiroku
* @since October 8th, 2023
*/
class NPCSpawnAction(spawnablePosition: SpawnablePosition, bucket: SpawnBucket, override val detail: NPCSpawnDetail) : SingleEntitySpawnAction<NPCEntity>(spawnablePosition, bucket, detail) {
class NPCSpawnAction(spawnablePosition: SpawnablePosition, bucket: String, override val detail: NPCSpawnDetail) : SingleEntitySpawnAction<NPCEntity>(spawnablePosition, bucket, detail) {
override fun createEntity(): NPCEntity {
val npc = NPCEntity(spawnablePosition.world)
npc.npc = detail.npcClass
@@ -11,13 +11,11 @@ package com.cobblemon.mod.common.api.spawning.detail
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.npc.NPCClass
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.util.asExpression
import com.google.gson.annotations.SerializedName
import kotlin.math.ceil
/**
* A [SpawnDetail] describing an [NPCEntity] spawn.
@@ -51,7 +49,7 @@ class NPCSpawnDetail : SpawnDetail() {
override fun createSpawnAction(
spawnablePosition: SpawnablePosition,
bucket: SpawnBucket,
bucket: String,
selectionData: SpawnSelectionData
) = NPCSpawnAction(spawnablePosition, bucket, this)
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
import com.cobblemon.mod.common.util.weightedSelection
@@ -54,8 +53,10 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
var pokemon: PokemonProperties = PokemonProperties()
val levelRange: IntRange? = null
var levelRangeOffset: IntRange? = null
val herdLevelRange: IntRange? = null
var dropTable: DropTable? = null
var isLeader: Boolean? = null
var isLeader: Boolean = false
var isFollower: Boolean = true
var weight: Float = 1F
var maxTimes = 10
var heldItem: ResourceLocation? = null
@@ -83,7 +84,7 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
val herdable = getValidHerdMembers(selectionData)
val herdCounts = getHerdMemberCounts(selectionData)
val leaderIsPossible = herdable.any { it.levelRange?.contains(level) != false && it.isLeader == true }
val leaderIsPossible = herdable.any { it.herdLevelRange?.contains(level) != false && it.isLeader }
val leaderIsSelected = herdCounts.any { it.key?.isLeader == true && it.value > 0 }
return leaderIsPossible && !leaderIsSelected
}
@@ -98,14 +99,16 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
override fun createSpawnAction(
spawnablePosition: SpawnablePosition,
bucket: SpawnBucket,
bucket: String,
selectionData: SpawnSelectionData
): PokemonSpawnAction {
val validHerdMembers = getValidHerdMembers(selectionData)
var searchedForLeader = false
val herdable = if (lacksPossibleLeader(selectionData)) {
validHerdMembers.filter { it.isLeader == true }
searchedForLeader = true
validHerdMembers.filter { it.isLeader }
} else {
validHerdMembers
validHerdMembers.filter { it.isFollower }
}.weightedSelection { it.weight } ?: herdablePokemon[0]
val level = selectionData.context[herdLevelKey] as? Int ?: 1
@@ -134,7 +137,7 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
heldItem = heldItem,
levelRange = levelRange
).also {
if (herdable.isLeader == true) {
if (herdable.isLeader && searchedForLeader) {
it.labels += HERD_LEADER
}
}
@@ -153,7 +156,7 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
val count = counts[herdable] ?: 0
return@filter when {
count >= herdable.maxTimes -> false
herdable.levelRange != null && level !in herdable.levelRange -> false
herdable.herdLevelRange != null && level !in herdable.herdLevelRange -> false
else -> true
}
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.feature.SeasonFeatureHandler
@@ -26,7 +25,7 @@ import net.minecraft.world.item.ItemStack
*/
class PokemonSpawnAction(
spawnablePosition: SpawnablePosition,
bucket: SpawnBucket,
bucket: String,
override val detail: SpawnDetail,
/**
* The [PokemonProperties] that are about to be used. When using it, a copy will be taken.
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
@@ -104,7 +103,8 @@ class PokemonSpawnDetail : SpawnDetail() {
}
override fun createSpawnAction(
spawnablePosition: SpawnablePosition, bucket: SpawnBucket,
spawnablePosition: SpawnablePosition,
bucket: String,
selectionData: SpawnSelectionData
): SingleEntitySpawnAction<PokemonEntity> {
val levelRange = pokemon.deriveLevelRange(levelRange)
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.entity.SpawnEvent
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.world.entity.Entity
@@ -26,7 +25,7 @@ import net.minecraft.world.entity.MobSpawnType
*/
abstract class SingleEntitySpawnAction<T : Entity>(
spawnablePosition: SpawnablePosition,
bucket: SpawnBucket,
bucket: String,
detail: SpawnDetail
) : SpawnAction<EntitySpawnResult>(spawnablePosition, bucket, detail) {
abstract fun createEntity(): T?
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import java.util.concurrent.CompletableFuture
@@ -21,7 +20,7 @@ import java.util.concurrent.CompletableFuture
*/
abstract class SpawnAction<R>(
val spawnablePosition: SpawnablePosition,
val bucket: SpawnBucket,
val bucket: String,
open val detail: SpawnDetail
) {
val labels = mutableListOf<String>()
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.ModDependant
import com.cobblemon.mod.common.api.molang.MoLangFunctions.queryStructOf
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.condition.CompositeSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.multiplier.WeightMultiplier
@@ -54,7 +53,7 @@ abstract class SpawnDetail : ModDependant {
var displayName: String? = null
@SerializedName("spawnablePositionType", alternate = ["context"])
lateinit var spawnablePositionType: SpawnablePositionType<*>
var bucket = SpawnBucket("", 0F)
var bucket = ""
var conditions = mutableListOf<SpawningCondition<*>>()
var anticonditions = mutableListOf<SpawningCondition<*>>()
var compositeCondition: CompositeSpawningCondition? = null
@@ -79,7 +78,7 @@ abstract class SpawnDetail : ModDependant {
"weight" to { DoubleValue(weight) },
"percentage" to { DoubleValue(percentage) },
"id" to { StringValue(id) },
"bucket" to { StringValue(bucket.name) },
"bucket" to { StringValue(bucket) },
"width" to { DoubleValue(width.toDouble()) },
"height" to { DoubleValue(height.toDouble()) },
"spawnable_position_type" to { StringValue(spawnablePositionType.name) },
@@ -136,6 +135,10 @@ abstract class SpawnDetail : ModDependant {
containsNullValues = true
LOGGER.error("Spawn Detail with id $id is invalid as it contains invalid values in its anticonditions (commonly caused by trailing comma in biomes or other arrays)")
}
if (bucket.isBlank()) {
containsNullValues = true
LOGGER.error("Spawn Detail with id $id is invalid as it does not have a bucket assigned")
}
return super.isModDependencySatisfied() && !containsNullValues
}
@@ -163,7 +166,7 @@ abstract class SpawnDetail : ModDependant {
*/
fun choose(
spawnablePosition: SpawnablePosition,
bucket: SpawnBucket,
bucket: String,
selectionData: SpawnSelectionData
): SpawnAction<*> {
val action = createSpawnAction(spawnablePosition, bucket, selectionData)
@@ -175,10 +178,10 @@ abstract class SpawnDetail : ModDependant {
return action
}
/** Instantiates an action at the given [SpawnablePosition] for the given [SpawnBucket]. */
/** Instantiates an action at the given [SpawnablePosition] for the given spawn bucket. */
protected abstract fun createSpawnAction(
spawnablePosition: SpawnablePosition,
bucket: SpawnBucket,
bucket: String,
selectionData: SpawnSelectionData
): SpawnAction<*>
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.detail
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnLoader
import com.cobblemon.mod.common.api.spawning.SpawnSet
import com.cobblemon.mod.common.api.spawning.condition.PrecalculationResult
@@ -61,12 +60,13 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
}
val details = mutableListOf<SpawnDetail>()
/** Tracks which buckets are in use by the pool, to prevent spawners for rolling buckets that don't exist. */
val buckets = mutableListOf<String>()
var precalculation: PrecalculationResult<*> = RootPrecalculation.generate(details, emptyList())
val precalculators = mutableListOf<SpawningPrecalculation<*>>()
override fun iterator() = details.iterator()
fun addPrecalculators(vararg precalculators: SpawningPrecalculation<*>): SpawnPool {
this.precalculators.addAll(precalculators)
precalculate()
@@ -88,6 +88,9 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
* be slow, especially if there are many precalculators and spawns.
*/
fun precalculate() {
buckets.clear()
buckets.addAll(details.asSequence().map(SpawnDetail::bucket).distinct())
if (precalculators.isEmpty()) {
precalculation = RootPrecalculation.generate(details, emptyList())
} else {
@@ -103,7 +106,7 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
* to leverage the precalculation to get a smaller list of spawns as quickly
* as possible.
*/
fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail> {
fun retrieve(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail> {
return precalculation.retrieve(bucket, spawnablePosition)
}
@@ -145,7 +145,7 @@ class FishingSpawnCause(
return
}
pokemonEntity.pokemon.isAlpha = true
pokemonEntity.pokemon.initializeMovesetWithRandomTm(2)
pokemonEntity.pokemon.initializeMovesetFromDefault()
if (!pokemonEntity.level().isClientSide) {
// Alpha status is applied after entity creation in bait flows, so rebuild the brain
// to ensure alpha-only sensors/memories are actually attached.
@@ -8,19 +8,19 @@
package com.cobblemon.mod.common.api.spawning.influence
import com.cobblemon.mod.common.api.spawning.SpawnBucket
/**
* A [SpawningInfluence] that multiplies bucket weights by the provided values
* and then normalizes the resulting weights so that their total adds up to 100.
*
* No longer used by the mod, but kept for external suers.
*/
class BucketMultiplyingInfluence(
val multipliers: Map<String, Float>,
) : SpawningInfluence {
override fun affectBucketWeights(bucketWeights: MutableMap<SpawnBucket, Float>) {
val updates = mutableMapOf<SpawnBucket, Float>()
override fun affectBucketWeights(bucketWeights: MutableMap<String, Float>) {
val updates = mutableMapOf<String, Float>()
for ((bucket, weight) in bucketWeights) {
val multiplier = multipliers[bucket.name]
val multiplier = multipliers[bucket]
if (multiplier != null) {
updates[bucket] = weight * multiplier
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.spawning.influence
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import kotlin.math.pow
/**
@@ -33,7 +32,7 @@ open class BucketNormalizingInfluence(
val gradient: Float = 0.2F,
val firstTier: Float = 1.29F
) : SpawningInfluence {
override fun affectBucketWeights(bucketWeights: MutableMap<SpawnBucket, Float>) {
override fun affectBucketWeights(bucketWeights: MutableMap<String, Float>) {
if (tier == 0) {
return
}
@@ -150,7 +150,7 @@ class SaccharineLogSlatheredInfluence(val pos: BlockPos? = null) : SpawningInflu
val chance = Cobblemon.config.honeySlatherAlphaChance
if (chance > 0 && Random.nextInt(chance) == 0) {
pokemon.isAlpha = true
pokemon.initializeMovesetWithRandomTm(2)
pokemon.initializeMovesetFromDefault()
}
}
@@ -21,6 +21,8 @@ import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.AlphaLevelMatchingSensor
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
/**
@@ -47,6 +49,13 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
Effects.getEffectFunction(effect.type)?.invoke(entity, effect)
}
}
if (entity.pokemon.isAlpha) {
val spawningPlayer = action.spawnablePosition.cause.entity as? ServerPlayer
if (spawningPlayer != null) {
AlphaLevelMatchingSensor.applyLevelMatching(entity, spawningPlayer)
}
}
}
}
@@ -130,4 +139,4 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
if (used) markUsed()
return super.affectWeight(detail, spawnablePosition, newWeight)
}
}
}
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.spawning.influence
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
@@ -39,9 +38,9 @@ interface SpawningInfluence {
/** Applies some influence over the entity that's been spawned. */
fun affectSpawn(action: SpawnAction<*>, entity: Entity) {}
/** Applies some influence over the weight of spawn buckets. */
fun affectBucketWeights(bucketWeights: MutableMap<SpawnBucket, Float>) {}
fun affectBucketWeights(bucketWeights: MutableMap<String, Float>) {}
/** Normalizes all bucket weights to add up to 100 */
fun normalizeBucketWeights(bucketWeights: MutableMap<SpawnBucket, Float>) {
fun normalizeBucketWeights(bucketWeights: MutableMap<String, Float>) {
val sum = bucketWeights.values.sum()
val to100 = 100F / sum
bucketWeights.keys.toList().forEach {
@@ -56,5 +55,5 @@ interface SpawningInfluence {
*
* You should make sure the spawn position satisfies any spawn details that you inject.
*/
fun injectSpawns(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail>? = null
fun injectSpawns(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail>? = null
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.preset
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
import com.cobblemon.mod.common.util.adapters.RegisteredSpawnablePositionAdapter
import com.google.gson.GsonBuilder
@@ -39,11 +38,34 @@ class BestSpawnerConfig {
"surface" to 0.01F,
"seafloor" to 1F
)
val buckets = mutableListOf(
SpawnBucket("common", 94.3F),
SpawnBucket("uncommon", 5F),
SpawnBucket("rare", 0.5F),
SpawnBucket("ultra-rare", 0.2F)
val worldBuckets = mutableMapOf(
"common" to 94F,
"uncommon" to 5F,
"rare" to 0.5F,
"ultra-rare" to 0.2F,
"boss" to 0.3F,
)
val fishingBuckets = mutableMapOf(
"common" to 83.25F,
"uncommon" to 11.25F,
"rare" to 4.125F,
"ultra-rare" to 1.375F
)
val activatedHabitatBuckets: MutableMap<String, Float> = mutableMapOf(
"common" to 83.25F,
"uncommon" to 11.25F,
"rare" to 4.125F,
"ultra-rare" to 1.375F
)
val pokeSnackBuckets = mutableMapOf(
"common" to 83.25F,
"uncommon" to 11.25F,
"rare" to 4.125F,
"ultra-rare" to 1.375F
)
companion object {
@@ -8,13 +8,12 @@
package com.cobblemon.mod.common.api.spawning.preset
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnDetailPresets
import com.cobblemon.mod.common.api.spawning.SpawnLoader
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.multiplier.WeightMultiplier
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
import com.cobblemon.mod.common.util.MergeMode
import com.cobblemon.mod.common.util.adapters.SpawnDetailAdapter
import com.google.gson.JsonObject
@@ -41,7 +40,7 @@ import com.google.gson.annotations.SerializedName
* @since July 8th, 2022
*/
abstract class SpawnDetailPreset {
var bucket: SpawnBucket? = null
var bucket: String? = null
var spawnDetailType: String? = null
@SerializedName("spawnablePositionType", alternate = ["context"])
var spawnablePositionType: SpawnablePositionType<*>? = null
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.spawning.selection
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
@@ -88,12 +87,12 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
class SpawnablePositionSelectionData(
val spawner: Spawner,
val spawnablePositions: List<SpawnablePosition>,
val selectingSpawnInformation: MutableMap<SpawnBucket, SpawnablePositionBucketSelectionData>,
val selectingSpawnInformation: MutableMap<String, SpawnablePositionBucketSelectionData>,
): SpawnSelectionData {
override val spawnActions = mutableListOf<SpawnAction<*>>()
override val context = mutableMapOf<String, Any>()
fun getDataForBucket(bucket: SpawnBucket): SpawnablePositionBucketSelectionData {
fun getDataForBucket(bucket: String): SpawnablePositionBucketSelectionData {
val existing = selectingSpawnInformation[bucket]
if (existing != null) {
return existing
@@ -130,14 +129,14 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
spawner: Spawner,
spawnablePositions: List<SpawnablePosition>
): SpawnablePositionSelectionData {
val selectingSpawnInformation: MutableMap<SpawnBucket, SpawnablePositionBucketSelectionData> = mutableMapOf()
val selectingSpawnInformation: MutableMap<String, SpawnablePositionBucketSelectionData> = mutableMapOf()
return SpawnablePositionSelectionData(spawner, spawnablePositions, selectingSpawnInformation)
}
override fun selectSpawnAction(
spawner: Spawner,
bucket: SpawnBucket,
bucket: String,
selectionData: SpawnablePositionSelectionData,
): SpawnAction<*>? {
val selectingSpawnInformation = selectionData.getDataForBucket(bucket) ?: return null
@@ -149,7 +148,7 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
if (percentSum > 100) {
Cobblemon.LOGGER.warn(
"""
A spawn list for ${spawner.name} exceeded 100% on percentage sums in bucket ${bucket.name}...
A spawn list for ${spawner.name} exceeded 100% on percentage sums in bucket $bucket...
This means you don't understand how this option works.
""".trimIndent()
)
@@ -186,7 +185,7 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
override fun getTotalWeights(
spawner: Spawner,
bucket: SpawnBucket,
bucket: String,
spawnablePositions: List<SpawnablePosition>
): Map<SpawnDetail, Float> {
val selectionData = getSelectionData(spawner, spawnablePositions).getDataForBucket(bucket)
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.spawning.selection
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
@@ -105,7 +104,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
override val spawnActions = mutableListOf<SpawnAction<*>>()
override val context = mutableMapOf<String, Any>()
val bucketData = mutableMapOf<SpawnBucket, MutableMap<SpawnablePositionType<*>, SpawnablePositionSelectionData>>()
val bucketData = mutableMapOf<String, MutableMap<SpawnablePositionType<*>, SpawnablePositionSelectionData>>()
override fun removeSpawnDetails(shouldRemove: (SpawnDetail) -> Boolean) {
bucketData.values.forEach {
@@ -121,7 +120,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
}
}
fun getDataForBucket(bucket: SpawnBucket): MutableMap<SpawnablePositionType<*>, SpawnablePositionSelectionData> {
fun getDataForBucket(bucket: String): MutableMap<SpawnablePositionType<*>, SpawnablePositionSelectionData> {
bucketData[bucket]?.let { return it }
val spawnablePositionTypeToSpawns = mutableMapOf<SpawnablePositionType<*>, SpawnablePositionSelectionData>()
@@ -149,7 +148,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
override fun selectSpawnAction(
spawner: Spawner,
bucket: SpawnBucket,
bucket: String,
selectionData: SeparatedSelectionData
): SpawnAction<*>? {
val bucketData = selectionData.getDataForBucket(bucket)
@@ -172,7 +171,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
if (percentSum > 100) {
LOGGER.warn(
"""
A spawn list for ${spawner.name} exceeded 100% on percentage sums in bucket ${bucket.name}...
A spawn list for ${spawner.name} exceeded 100% on percentage sums in bucket $bucket...
This means you don't understand how this option works.
""".trimIndent()
)
@@ -244,7 +243,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
override fun getTotalWeights(
spawner: Spawner,
bucket: SpawnBucket,
bucket: String,
spawnablePositions: List<SpawnablePosition>
): Map<SpawnDetail, Float> {
val selectionData = getSelectionData(spawner, spawnablePositions).getDataForBucket(bucket)
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.spawning.selection
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
@@ -33,13 +32,13 @@ interface SpawningSelector<T : SpawnSelectionData> {
fun selectSpawnAction(
spawner: Spawner,
bucket: SpawnBucket,
bucket: String,
selectionData: T
): SpawnAction<*>?
fun select(
spawner: Spawner,
bucketSelector: () -> SpawnBucket,
bucketSelector: () -> String,
spawnablePositions: List<SpawnablePosition>,
maxSpawns: Int
): List<SpawnAction<*>> {
@@ -65,7 +64,7 @@ interface SpawningSelector<T : SpawnSelectionData> {
return spawnActions
}
fun getProbabilities(spawner: Spawner, bucket: SpawnBucket, spawnablePositions: List<SpawnablePosition>): Map<SpawnDetail, Float> {
fun getProbabilities(spawner: Spawner, bucket: String, spawnablePositions: List<SpawnablePosition>): Map<SpawnDetail, Float> {
val weights = getTotalWeights(spawner, bucket, spawnablePositions)
val totalWeight = weights.values.sum()
val percentages = mutableMapOf<SpawnDetail, Float>()
@@ -73,5 +72,5 @@ interface SpawningSelector<T : SpawnSelectionData> {
return percentages
}
fun getTotalWeights(spawner: Spawner, bucket: SpawnBucket, spawnablePositions: List<SpawnablePosition>): Map<SpawnDetail, Float>
fun getTotalWeights(spawner: Spawner, bucket: String, spawnablePositions: List<SpawnablePosition>): Map<SpawnDetail, Float>
}
@@ -25,7 +25,8 @@ import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
open class BasicSpawner(
override val name: String,
override var spawnPool: SpawnPool,
override var maxPokemonPerChunk: Float = Cobblemon.config.pokemonPerChunk
override var maxPokemonPerChunk: Float = Cobblemon.config.pokemonPerChunk,
override val buckets: Map<String, Float>
) : Spawner {
override var selector: SpawningSelector<*> = SpawningSelector.DEFAULT
override var generator: SpawningZoneGenerator = Cobblemon.spawningZoneGenerator
@@ -8,11 +8,11 @@
package com.cobblemon.mod.common.api.spawning.spawner
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonPoiTypes
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence.Companion.TYPICAL_VARIATION
@@ -72,16 +72,9 @@ object FishingSpawnerFactory {
fun createSharedSpawner(): BasicSpawner {
return BasicSpawner(
name = "fishing",
spawnPool = spawnPool
).also { spawner ->
spawner.influences += BucketMultiplyingInfluence(
multipliers = mapOf(
"uncommon" to 2.25f,
"rare" to 5.5f,
"ultra-rare" to 5.5f,
)
)
}
spawnPool = spawnPool,
buckets = Cobblemon.bestSpawner.config.fishingBuckets,
)
}
fun findHabitatInfluences(world: ServerLevel, position: BlockPos, spawner: Spawner): Array<HabitatBlockEntity> {
@@ -11,8 +11,8 @@ package com.cobblemon.mod.common.api.spawning.spawner
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import net.minecraft.server.level.ServerLevel
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
/**
* A spawner that works within a fixed area. Instances provide the center point and the radii and then the spawner
@@ -24,12 +24,13 @@ import net.minecraft.core.BlockPos
open class FixedAreaSpawner(
name: String,
spawnPool: SpawnPool,
buckets: Map<String, Float>,
val world: ServerLevel,
val position: BlockPos,
val horizontalRadius: Int,
val verticalRadius: Int,
maxPokemonPerChunk: Float = Cobblemon.config.pokemonPerChunk
) : BasicSpawner(name, spawnPool, maxPokemonPerChunk) {
) : BasicSpawner(name, spawnPool, maxPokemonPerChunk, buckets) {
fun run(cause: SpawnCause, maxSpawns: Int? = null): List<Any> {
return runForArea(
zoneInput = getZoneInput(cause),
@@ -8,20 +8,21 @@
package com.cobblemon.mod.common.api.spawning.spawner
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.config
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.util.getPlayer
import com.cobblemon.mod.common.util.nextBetween
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.util.Mth.PI
import net.minecraft.util.Mth.ceil
import java.util.*
import java.util.UUID
import kotlin.math.atan
import kotlin.math.cos
import kotlin.math.sin
import kotlin.random.Random
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.util.Mth.PI
import net.minecraft.util.Mth.ceil
/**
* A spawner that works around a single player. It will do basic tracking of a player's speed
@@ -35,7 +36,8 @@ open class PlayerSpawner(
spawnPool: SpawnPool
) : BasicSpawner(
name = player.name.string,
spawnPool = spawnPool
spawnPool = spawnPool,
buckets = Cobblemon.bestSpawner.config.worldBuckets
) {
val uuid: UUID = player.uuid
@@ -8,11 +8,11 @@
package com.cobblemon.mod.common.api.spawning.spawner
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
@@ -61,15 +61,6 @@ object PokeSnackSpawnerFactory {
firstTier = 1.2F
)
},
{ _ ->
BucketMultiplyingInfluence(
mapOf(
"uncommon" to 2.25f,
"rare" to 5.5f,
"ultra-rare" to 5.5f,
)
)
},
{ ctx ->
SpawnBaitInfluence(effects = ctx.baitEffects)
},
@@ -81,6 +72,7 @@ object PokeSnackSpawnerFactory {
return FixedAreaSpawner(
name = ctx.name,
spawnPool = spawnPool,
buckets = Cobblemon.bestSpawner.config.pokeSnackBuckets,
world = ctx.world,
position = ctx.pos,
horizontalRadius = ctx.horizontalRadius,
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.entity.SpawnBucketChosenEvent
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
import com.cobblemon.mod.common.api.spawning.detail.EntitySpawnResult
@@ -26,6 +25,7 @@ import com.cobblemon.mod.common.api.spawning.position.calculators.SpawnablePosit
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.isBoxLoaded
import com.cobblemon.mod.common.util.removeIf
import com.cobblemon.mod.common.util.squeezeWithinBounds
import com.cobblemon.mod.common.util.toVec3f
import com.cobblemon.mod.common.util.weightedSelection
@@ -52,6 +52,7 @@ import net.minecraft.world.phys.Vec3
interface Spawner {
val name: String
val influences: MutableList<SpawningInfluence>
val buckets: Map<String, Float>
var spawnPool: SpawnPool
var selector: SpawningSelector<*>
var generator: SpawningZoneGenerator
@@ -65,7 +66,7 @@ interface Spawner {
const val ENTITY_LIMIT_CHUNK_RANGE = 3
}
fun getMatchingSpawns(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail> {
fun getMatchingSpawns(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail> {
val spawns = mutableListOf<SpawnDetail>()
spawns.addAll(spawnPool.retrieve(bucket, spawnablePosition).filter { it.isSatisfiedBy(spawnablePosition) })
spawnablePosition.influences.forEach { influence ->
@@ -172,11 +173,12 @@ interface Spawner {
fun copyInfluences() = influences.filter { !it.isExpired() }.toMutableList()
fun chooseBucket(cause: SpawnCause, influences: List<SpawningInfluence>): SpawnBucket {
val buckets = Cobblemon.bestSpawner.config.buckets
val bucketWeights = buckets.associateWith { it.weight }.toMutableMap()
fun chooseBucket(cause: SpawnCause, influences: List<SpawningInfluence>): String {
val bucketWeights = buckets.toMutableMap()
influences.forEach { it.affectBucketWeights(bucketWeights) }
val bucket = bucketWeights.entries.weightedSelection { it.value }?.key ?: buckets.first()
val usedBuckets = spawnPool.buckets.intersect(bucketWeights.keys)
bucketWeights.removeIf { it.key !in usedBuckets }
val bucket = bucketWeights.entries.weightedSelection { it.value }?.key ?: buckets.keys.first()
val event = SpawnBucketChosenEvent(
spawner = this,
spawnCause = cause,
@@ -51,6 +51,8 @@ object CobblemonBiomeTags {
@JvmField
val IS_FUNGUS = create("nether/is_fungus")
@JvmField
val IS_WASTELAND = create("nether/is_wasteland")
@JvmField
val IS_GLACIAL = create("is_glacial")
@JvmField
val IS_TEMPERATE_OCEAN = create("is_temperate_ocean")
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.moves.adapters.MoveTemplateAdapter
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.TMObtainMethodAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
@@ -70,5 +71,7 @@ object TechnicalMachines : JsonDataRegistry<TechnicalMachine> {
fun getByResourceLocation(resourceLocation: ResourceLocation) = tmMap[resourceLocation]
fun getAllResourceLocations() = tmMap.keys.toSet()
override fun sync(player: ServerPlayer) {}
override fun sync(player: ServerPlayer) {
TechnicalMachineRegistrySyncPacket(tmMap.values.toList()).sendToPlayer(player)
}
}
@@ -68,7 +68,7 @@ object ShowdownInterpreter {
updateInstructionParser["-endability"] = { _, _, message, _ -> EndAbilityInstruction(message) }
updateInstructionParser["-end"] = { _, _, message, _ -> EndInstruction(message) }
updateInstructionParser["-enditem"] = { _, _, message, _ -> EndItemInstruction(message) }
updateInstructionParser["-fail"] = { _, _, message, _ -> FailInstruction(message) }
updateInstructionParser["-fail"] = { battle, _, message, _ -> FailInstruction(battle, message) }
updateInstructionParser["faint"] = { battle, _, message, _ -> FaintInstruction(battle, message) }
updateInstructionParser["-fieldactivate"] = { _, _, message, _ -> FieldActivateInstruction(message) }
updateInstructionParser["-fieldend"] = { _, _, message, _ -> FieldEndInstruction(message) }
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.battles.PassActionResponse
import com.cobblemon.mod.common.battles.ShowdownActionResponse
import com.cobblemon.mod.common.battles.ShowdownMoveset
import com.cobblemon.mod.common.battles.SwitchActionResponse
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
/**
* AI that randomly chooses a move from its moveset at a random target.
@@ -40,17 +41,19 @@ class RandomBattleAI : BattleAI {
return SwitchActionResponse(switchTo.uuid)
}
if (moveset == null) {
if (moveset == null)
return PassActionResponse
val move = moveset.moves.filter { it.canBeUsed() }.randomOrNull()
if (move == null) {
if (moveset.moves.any { it.id == "struggle" })
return MoveActionResponse("struggle")
else throw IllegalActionChoiceException(activeBattlePokemon.actor,
"No valid AI move choices, but Showdown never injected Struggle!")
}
val move = moveset.moves
.filter { it.canBeUsed() }
.filter { it.mustBeUsed() || it.target.targetList(activeBattlePokemon)?.isEmpty() != true }
.randomOrNull()
?: return MoveActionResponse("struggle")
val target = if (move.mustBeUsed()) null else move.target.targetList(activeBattlePokemon)
return if (target == null) {
return if (target.isNullOrEmpty()) {
MoveActionResponse(move.id)
} else {
// prioritize opponents rather than allies
@@ -25,6 +25,7 @@ import com.cobblemon.mod.common.battles.ai.strongBattleAI.AIUtility
import com.cobblemon.mod.common.battles.ai.strongBattleAI.ActiveTracker
import com.cobblemon.mod.common.battles.ai.strongBattleAI.TrackerPokemon
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import kotlin.random.Random
import kotlin.collections.associateWith
@@ -94,14 +95,14 @@ class StrongBattleAI(skill: Int) : BattleAI {
return null to 0.0 // we do not care about moves that dont target opponents during damage calculations
val singleTargetList = move.first.target.targetList.invoke(attacker)?.map { it as ActiveBattlePokemon }?.filter { it.battlePokemon != null }
val multiTargetList = attacker.getMultiTargetList(move.first.target)?.map { it as ActiveBattlePokemon }?.filter { it.battlePokemon != null }
if (singleTargetList != null && singleTargetList.isNotEmpty()) {
if (!singleTargetList.isNullOrEmpty()) {
// figure out target that will take the most damage
val potentialTargets = activeTracker.opponentSide.activePokemon
.filter { opp -> opp.id in singleTargetList.map { it.battlePokemon!!.uuid } }
.map { opp -> singleTargetList.first { it.battlePokemon!!.uuid == opp.id} to calculateDamage(move.first, attackerTracker, opp) }
return potentialTargets.maxBy { it.second }
} else if (multiTargetList != null && multiTargetList.isNotEmpty()) {
} else if (!multiTargetList.isNullOrEmpty()) {
val (allies, opponents) = multiTargetList.partition { it.isAllied(attacker) }
// weigh up allied damage against opponents
val totalOpponentDamage = activeTracker.opponentSide.activePokemon
@@ -188,10 +189,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
// function for finding the most damaging moves in the moveset
fun mostDamagingMove(selectedMove: InBattleMove, moveset: ShowdownMoveset?, mon: TrackerPokemon, opponent: TrackerPokemon): Boolean {
if (moveset != null) {
for (move in moveset.moves.filter { !it.disabled && it.id != selectedMove.id}) {
if (calculateDamage(move, mon, opponent) > calculateDamage(selectedMove, mon, opponent)) {
return false
}
@@ -251,18 +250,19 @@ class StrongBattleAI(skill: Int) : BattleAI {
val availableMoves = moveset.moves.filter { it.canBeUsed() }.map { Pair(it, Moves.getByName(it.id)!!)}
if (!checkSkillLevel()){
val move = availableMoves
.filter { it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
.randomOrNull()
?: return MoveActionResponse("struggle")
return chooseMove(move.first, activeBattlePokemon)
val randomMove = availableMoves.randomOrNull()
if (randomMove == null) {
if (moveset.moves.any { it.id == "struggle" })
return MoveActionResponse("struggle")
else throw IllegalActionChoiceException(activeBattlePokemon.actor,
"No valid AI move choices, but Showdown never injected Struggle!")
}
if (!checkSkillLevel()) return chooseMove(randomMove.first, activeBattlePokemon)
// switch out based on current matchup on the field
if (checkSwitchOutSkill() && shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
considerSwitching(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, availableSwitches, battle, aiSide)
considerSwitching(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, availableSwitches, battle, aiSide)?.let { return it }
}
// If HP is below 30% and not switching out, always use the most damaging move
@@ -358,7 +358,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
}
}
considerAntiBoost(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves)
considerAntiBoost(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves)?.let { return it }
// Court Change
for (move in availableMoves) {
@@ -414,7 +414,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
}
}
considerInflictingStatus(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, battle, aiSide)
considerInflictingStatus(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, battle, aiSide)?.let { return it }
// Protect style moves
for (move in availableMoves) {
@@ -430,7 +430,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
}
}
findAndUseMostDamagingMove(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, moveset, battle, aiSide)
findAndUseMostDamagingMove(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, moveset, battle, aiSide)?.let { return it }
}
// healing wish (dealing with it here because you'd only use it if you should switch out anyway)
@@ -450,13 +450,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
}
activeTrackerPokemon.firstTurn = false
val move = availableMoves
.filter { it.first.canBeUsed() }
.filter { it.first.mustBeUsed() || it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
.randomOrNull()
?: return MoveActionResponse("struggle")
return chooseMove(move.first, activeBattlePokemon)
return chooseMove(randomMove.first, activeBattlePokemon)
}
// estimate mid-battle switch in value
@@ -978,12 +972,12 @@ class StrongBattleAI(skill: Int) : BattleAI {
val bestMove = moveValues.maxBy { it.value.second }
val target = if (bestMove.key.first.mustBeUsed()) null else bestMove.value.first
return MoveActionResponse(bestMove.key.first.id, target?.getPNX())
return chooseMove(bestMove.key.first, activeBattlePokemon, target)
}
private fun chooseMove(move: InBattleMove, activeBattlePokemon: ActiveBattlePokemon, target: ActiveBattlePokemon? = null): MoveActionResponse {
val targets = if (move.mustBeUsed()) null else move.target.targetList(activeBattlePokemon)
if (targets == null)
if (targets.isNullOrEmpty())
return MoveActionResponse(move.id)
else {
val chosenTarget = target ?: targets.filter { !it.isAllied(activeBattlePokemon) }.randomOrNull() ?: targets.random()
@@ -22,8 +22,8 @@ import com.cobblemon.mod.common.util.battleLang
* @author Hunter
* @since September 25th, 2022
*/
class FailInstruction(val message: BattleMessage): InterpreterInstruction {
class FailInstruction(val battle: PokemonBattle, val message: BattleMessage): InterpreterInstruction {
val target = message.battlePokemon(0, battle)
override fun invoke(battle: PokemonBattle) {
battle.dispatchWaiting(1.5F){
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
@@ -137,6 +137,8 @@ class MoveInstruction(
val subsequentInstructions = instructionSet.findInstructionsCausedBy(this)
val missedTargets = subsequentInstructions.filterIsInstance<MissInstruction>().mapNotNull { it.target }
val failed = subsequentInstructions.any { it is FailInstruction }
val failedTargets = subsequentInstructions.filterIsInstance<FailInstruction>().mapNotNull { it.target }
val hitCountInstruction = subsequentInstructions.filterIsInstance<HitCountInstruction>().firstOrNull()
runtime.environment.query.addFunction("missed") { params ->
@@ -148,6 +150,15 @@ class MoveInstruction(
}
}
runtime.environment.query.addFunction("failed") { params ->
if (params.params.size == 0) {
return@addFunction DoubleValue(failed)
} else {
val entityUUID = params.getString(0)
return@addFunction DoubleValue(failedTargets.any { it.entity?.stringUUID == entityUUID })
}
}
val hurtTargets = subsequentInstructions.filterIsInstance<DamageInstruction>().mapNotNull { it.expectedTarget }
runtime.environment.query.addFunction("hurt") { params ->
if (params.params.size == 0) {
@@ -66,6 +66,7 @@ class GraalShowdownService : ShowdownService {
.allowArrayAccess(true)
.allowListAccess(true)
.allowMapAccess(true)
.allowAccessAnnotatedBy(Export::class.java)
.build()
context = Context.newBuilder("js")
.allowIO(true)
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.farming.ApricornHarvestEvent
@@ -176,7 +177,7 @@ class ApricornBlock(settings: Properties, val apricorn: Apricorn) : HorizontalDi
world.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, resetState))
if (!world.isClientSide) {
world.playSoundServer(position = pos.toVec3d(), sound = SoundEvents.ITEM_PICKUP, volume = 0.7F, pitch = 1.4F)
world.playSoundServer(position = pos.toVec3d(), sound = CobblemonSounds.APRICORN_HARVEST, volume = 1.0F, pitch = 1.0F)
if (world is ServerLevel && player is ServerPlayer) {
CobblemonEvents.APRICORN_HARVESTED.post(ApricornHarvestEvent(player, apricorn, world, pos))
@@ -203,6 +203,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
): InteractionResult {
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
if (player.getItemInHand(InteractionHand.MAIN_HAND).item is ShovelItem && getMulch(treeEntity) != MulchVariant.NONE) {
treeEntity.setMulch(MulchVariant.NONE, world, state, pos)
treeEntity.setChanged()
world.playSound(null, pos, CobblemonSounds.MULCH_REMOVE, SoundSource.BLOCKS, 0.6F, 1F)
this.spawnDestroyParticles(world, player, pos, state.setValue(AGE, 0))
@@ -127,7 +127,7 @@ class LecternBlock(properties: Properties): BaseEntityBlock(properties) {
else {
blockEntity.incrementViewerCount()
PokedexUIPacket(type = (blockEntity.getItemStack().item as PokedexItem).type, blockPos = blockPos).sendToPlayer(player as ServerPlayer)
level.playSoundServer(position = blockPos.toVec3d(), sound = CobblemonSounds.POKEDEX_OPEN, volume = 0.25F)
level.playSoundServer(position = blockPos.bottomCenter, sound = CobblemonSounds.POKEDEX_OPEN, volume = 0.25F)
}
}
}
@@ -287,7 +287,7 @@ class PCBlock(properties: Properties): BaseEntityBlock(properties), SimpleWaterl
PCLinkManager.addLink(ProximityPCLink(pc, player.uuid, baseEntity))
OpenPCPacket(pc).sendToPlayer(player)
world.playSoundServer(
position = blockPos.toVec3d(),
position = blockPos.bottomCenter,
sound = CobblemonSounds.PC_ON,
volume = 0.5F,
pitch = 1F
@@ -290,7 +290,7 @@ class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWater
PastureLinkManager.createLink(player.uuid, PastureLink(linkId, pcId, ResourceLocation.tryParse(world.dimensionTypeRegistration().registeredName)!!, getBasePosition(state, pos), perms))
world.playSoundServer(
position = pos.toVec3d(),
position = pos.bottomCenter,
sound = CobblemonSounds.PC_ON,
volume = 0.5F,
pitch = 1F
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.block
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.util.giveOrDropItemStack
import com.cobblemon.mod.common.util.isServerSide
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
@@ -285,7 +286,7 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
// Replace the consumed empty bottle with a honey bottle
player.setItemInHand(hand, ItemStack(Items.HONEY_BOTTLE));
} else {
player.addItem(Items.HONEY_BOTTLE.defaultInstance)
player.giveOrDropItemStack(Items.HONEY_BOTTLE.defaultInstance)
}
level.playSound(null, pos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS)

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