Compare commits

..
Author SHA1 Message Date
Guilherme Pereira 2e80924c68 fix broken skills 2026-06-19 12:00:08 -03:00
Guilherme Pereira 6749b39142 Merge branch 'poke-skills' into jack-pokeskills 2026-06-12 10:27:17 -03:00
Guilherme Pereira ff25416b07 Merge branch 'main' into poke-skills 2026-06-12 09:41:17 -03:00
Polymeta e15ac73b1b Merge branch 'fix-enchanted-fossil-items' into 'main'
Fix crash when using enchanted items in the ressurection machine

Closes #1973

See merge request cable-mc/cobblemon!2307
2026-06-11 21:48:56 +00:00
lionandPolymeta 6c6576c117 Fix crash when using enchanted items in the ressurection machine 2026-06-11 21:48:55 +00:00
Polymeta ebdfa7edc0 Merge branch 'fix-pokemon-properties-nickname-parsing-to-json' into 'main'
Add pokémon nickname when serializing and deserializing to json on pokémon properties

Closes #1981

See merge request cable-mc/cobblemon!2306
2026-06-11 13:48:21 +00:00
lionandPolymeta 297e8eae77 Add pokémon nickname when serializing and deserializing to json on pokémon properties 2026-06-11 13:48:21 +00:00
Polymeta ea8179018d Merge branch 'modded-discs-compat' into 'main'
Add modded discs compatibility with disc shelves

See merge request cable-mc/cobblemon!2305
2026-06-11 08:20:18 +00:00
lionandPolymeta 14fccfae1d Add modded discs compatibility with disc shelves 2026-06-11 08:20:18 +00: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
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
ewwww fdafb1e64a updated en_us 2026-05-22 21:35:48 -04:00
RedGenesectNinja bd525c8740 Implemented the rest of the Gen 4 alpha eyes 2026-05-21 04:30:28 -05:00
ewwww 209dee1d25 . 2026-05-21 03:48:37 -04: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
ewwww 5fda445274 cinderace tweak 2026-05-20 23:08:09 -04:00
Jerzykv ce0265e954 Goodra animation tweaks 2026-05-20 22:38:56 +02: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
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
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
ewwww 620002c165 chopped off gastly's tongue & poked zubat's eyes out 2026-05-20 01:45:14 -04:00
Sterrezo d89224a684 FIxed incorrectly named sound events for Galarian Ponyta and Rapidash cries 2026-05-19 14:15:05 +02:00
ewwww 856eb2a1bd pyro balling 2026-05-18 06:33:20 -04: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
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
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
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
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
jackowes bb81a44a11 - WIP pening pokeskills gui now on r+click and release chooses 2026-03-11 21:49:04 -05:00
jackowes 40dfca2294 - Take out icecube
- gui open on r+right click. Need to figure out how to exactly handle the choosing and displaying.
2026-03-10 22:37:23 -05:00
jackowes 5a40ced96b - bit of work on entity targeting
- the freeze is just a test
- add look at entity function
2026-03-08 23:09:06 -05:00
jackowes 3eb97b29a1 - WIP
- Delegation of pokeskill move action effects to the move that grants the effect itself.
- allow for targeting of arbitrary points in space with the current entity partcle spanwing logc.
TODO:
- add the self targeting logic.
- add out of battle entity targeting
- allow the target particles to play as if they hit.
2026-03-08 18:41:48 -05:00
jackowes d88de0b072 - Add dynamic expression to RunActionEffectKeyframe.kt that resolves at runtime to determine the action effect identifier.
- add some logging to avoid evil corporate silent json failure
- Add optional worldposition targeting to EntityParticlesActionEffectKeyframe.kt. If a target entity exists in the runtime context then ignore this but if no target entity exists and v.target vars are set then target that position with the particles.
2026-03-08 13:23:15 -05:00
jackowes 460c44248c - stoke (still needs the multiple levels and a few things ironed out) 2026-03-03 23:36:28 -06:00
jackowes a16668695c - got the sound working. need to add to the others but its just a temp sound rn anways
- add fertilizer skill logic (should I move it)
- still checking the species name wrong lol
2026-03-01 13:01:34 -06:00
jackowes fe5ebb5444 just sensed some gold and gems 2026-02-28 21:06:50 -06:00
jackowes c34e4c8bbc - iron ore locating working... it was very easy... I didn't realize the entity condition wasn't consuming a molang expression I gave it an evaluating it for t/f. oh well, had to learn all this at some point so maybe its not time wasted. it has me rambling in a commit message though. Are there character limits to commit messages?
- sound still bugged. might just be giving it an incorrect resource location?
2026-02-28 12:51:38 -06:00
jackowes 84e76a0a6d Initial iron sense logic. There's something I'm not getting with molang or action effects quite yet. 2026-02-27 23:00:57 -06:00
jackowes be70c1e8de Merge branch 'main' into poke-skills
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/storage/party/PlayerPartyStore.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/block/entity/PokemonPastureBlockEntity.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/pokemon/Pokemon.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/util/codec/internal/PokemonP3.kt
2026-02-26 18:12:49 -06:00
Guilherme Pereira fba40387bb add teleport poke skill 2025-11-21 01:22:20 -03:00
Guilherme Pereira 1217e6d101 Merge branch 'main' into poke-skills 2025-11-20 16:27:39 -03:00
Paul 905c410aee Added 'enabled' property to poke skills 2025-10-04 11:29:07 +10:00
Paul cea0c826c6 Merge remote-tracking branch 'origin/main' into poke-skills
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/util/codec/internal/PokemonP3.kt
2025-10-03 15:50:05 +10:00
Paul dc3b17df3b conflicto fixo 2025-09-21 13:01:01 +10:00
Paul 5602dee9ac Merge remote-tracking branch 'origin/main' into poke-skills
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/api/molang/MoLangFunctions.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/keybind/keybinds/PartySendBinding.kt
2025-09-21 12:47:03 +10:00
Paul 9e4137cc20 Tighten poke skill keybind time 2025-09-01 21:19:58 +10:00
Paul c92248f6e9 Added poke skill system with example quick_ride.json skill, some GUI improvements needed 2025-09-01 12:13:07 +10:00
1968 changed files with 54366 additions and 14915 deletions
+1
View File
@@ -24,6 +24,7 @@ eclipse
run
runClient
runServer
utilityscripts/implementation/*.txt
# Files from Forge MDK
forge*changelog.txt
+110 -27
View File
@@ -56,6 +56,7 @@
- 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
@@ -67,6 +68,7 @@
- Milotic
### Pokémon Added
#### Generation 3
- Wurmple
- Silcoon
- Beautifly
@@ -74,59 +76,55 @@
- Dustox
- Skitty
- Delcatty
- Seviper
- Zangoose
#### Generation 4
- Cherubi
- Cherrim
- Stunky
- Skuntank
#### Generation 5
- Audino
- Pawniard
- Bisharp
- Kingambit
#### 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
- Archaludon
- Applin
- Flapple
- Appletun
- Dipplin
- Hydrapple
#### Generation 9
- Nymble
- Lokix
- Kingambit
- Dipplin
- Archaludon
- Hydrapple
#### Regional Forms
- Sandshrew (Alolan)
- Sandslash (Alolan)
- Avalugg (Hisuian)
### Model updates for the following Pokémon
- Goomy
- Sliggoo
- Goodra
- Porygon
- Porygon2
- Porygon-Z
- Zubat
- Golbat
- Crobat
- Sandshrew (Alolan Form)
- Sandslash (Alolan Form)
- Yamask (Galarian Form)
- Avalugg (Hisuian Form)
### Model updates for the following Pokémon
@@ -136,11 +134,12 @@
- Zubat
- Golbat
- Crobat
- Ditto
- Porygon
- Porygon2
- Porygon-Z
- Skarmory
- Smoochum
- Jynx
- Popplio
- Brionne
@@ -148,17 +147,22 @@
- Fletchling
- Fletchinder
- Talonflame
- Sableye
- Mawile
- Goomy
- Sliggoo
- Goodra
- Nacli
- Naclstack
- Garganacl
- 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:
@@ -192,6 +196,12 @@
- Shedinja
- Skwovet
- Greedent
- Bidoof
- Cranidos
- Chatot
- Yamask
- Cofagrigus
- Luvdisc
#### Added sounds to the following moves
- Absorb
@@ -288,6 +298,9 @@
- 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
- Fixed a crash caused by adding enchanted items to the Resurrection Machine
### Fixes
- Fixed Croagunk's walkspeed
@@ -348,6 +361,7 @@
- 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.
- Fixed nicknames not being applied to Pokémon spawned from `spawn_pool_world` files
### Molang & Datapacks
- Added `moveset_builders` datapack folder for different styles of movesets.
@@ -371,15 +385,84 @@
- 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.
- 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
+2 -2
View File
@@ -1,9 +1,9 @@
import utilities.isSnapshot
import utilities.version
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import utilities.isSnapshot
import utilities.version
/*
*
@@ -20,6 +20,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
@Mixin(ClientPacketListener.class)
@@ -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();
}
}
@@ -10,7 +10,9 @@ package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.gui.components.StateSwitchingButton;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
import net.minecraft.network.chat.Component;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(RecipeBookComponent.class)
@@ -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();
}
@@ -15,9 +15,11 @@ import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.world.Containers;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeManager;
@@ -32,7 +34,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Optional;
@Mixin(BrewingStandBlockEntity.class)
public class BrewingStandBlockEntityMixin {
@@ -9,11 +9,17 @@
package com.cobblemon.mod.common.mixin.brewing;
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
import net.minecraft.world.inventory.BrewingStandMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@@ -19,6 +19,7 @@ import net.minecraft.client.Camera;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.phys.Vec3;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -10,7 +10,9 @@ package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.CobblemonRecipeCategories;
import com.cobblemon.mod.common.item.crafting.CookingPotBookCategory;
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe;
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase;
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGuiFactoryKt;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.client.keybind.keybinds.RidingFreelookBinding;
import com.cobblemon.mod.common.duck.RidePassenger;
@@ -67,6 +68,39 @@ public abstract class MouseHandlerMixin {
@Unique private double cobblemon$timeDelta;
@Inject(
method = "onPress",
at = @At("HEAD"),
cancellable = true
)
public void cobblemon$pokeskillGuiControl(long windowPointer, int button, int action, int modifiers, CallbackInfo ci) {
if (button == 0 && action == 1) {
// Make sure no menus are open already
if (this.minecraft.screen == null && this.minecraft.getOverlay() == null) {
// Check to see if party key is held
if (PartySendBinding.INSTANCE.getWasDown()) {
// Don't want to send out a pokemon if we let go of the key
PartySendBinding.INSTANCE.actioned();
//Open the actual gui
var player = Minecraft.getInstance().player;
var storage = CobblemonClient.INSTANCE.getStorage();
var selectedPokemon = storage.getParty().get(storage.getSelectedSlot());
if (selectedPokemon != null && player != null) {
//canApplyChange = false
var gui = InteractWheelGuiFactoryKt.createPokeSkillGui(player, selectedPokemon);
Minecraft.getInstance().setScreen(gui);
}
// Stop the rest of minecraft click logic like punching and using items
ci.cancel();
}
}
}
}
@Inject(
method = "onScroll",
at = @At(
@@ -97,10 +97,10 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.aspects.ALPHA_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.FORM_ASPECTS
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.MARK_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeature
import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatureProvider
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
@@ -114,7 +114,6 @@ import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.pokemon.transformation.triggers.BlockClickTrigger
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
@@ -273,8 +272,13 @@ object Cobblemon {
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { event ->
val player = event.player
val block = player.level().getBlockState(event.pos).block
val context = BlockClickTrigger.Context(block, player.level())
player.party().forEach { pokemon -> pokemon.triggerTransformations<BlockClickTrigger>(context) }
player.party().forEach { pokemon ->
pokemon.lockedEvolutions
.filterIsInstance<BlockClickEvolution>()
.forEach { evolution ->
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.level()))
}
}
}
PlatformEvents.CHANGE_DIMENSION.subscribe {
@@ -304,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)
}
@@ -316,7 +322,6 @@ object Cobblemon {
SHINY_ASPECT.register()
GENDER_ASPECT.register()
FORM_ASPECTS.register()
COSMETIC_SLOT_ASPECT.register()
CHARACTERISTIC_RAINBOW_ASPECT.register()
ALPHA_ASPECT.register()
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.CobblemonBehaviours.autoPokemonBehaviours
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.ai.CobblemonBehaviour
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
@@ -20,7 +19,16 @@ import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.BehaviourSyncPacket
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
import com.cobblemon.mod.common.util.adapters.BehaviourConfigAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionOrEntityVariableAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.MemoryModuleTypeAdapter
import com.cobblemon.mod.common.util.adapters.SensorTypeAdapter
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.endsWith
import com.google.gson.Gson
@@ -19,6 +19,7 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.server.packs.resources.PreparableReloadListener
import net.minecraft.tags.TagKey
import net.minecraft.world.inventory.MenuType
import net.minecraft.world.level.GameRules
import net.minecraft.world.level.ItemLike
import net.minecraft.world.level.biome.Biome
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import java.util.Optional
import java.util.UUID
import net.minecraft.core.BlockPos
import net.minecraft.core.GlobalPos
import net.minecraft.core.UUIDUtil
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import java.util.*
object CobblemonMemories {
val memories = mutableMapOf<String, MemoryModuleType<*>>()
@@ -24,26 +24,13 @@ import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.SetActiveTMPacketHandler
import com.cobblemon.mod.common.client.net.gui.SetTMMachineContainerDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
import com.cobblemon.mod.common.client.net.effect.*
import com.cobblemon.mod.common.client.net.gui.*
import com.cobblemon.mod.common.client.net.habitat.OpenHabitatBlockEditorHandler
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureConflictFlagHandler
import com.cobblemon.mod.common.client.net.pasture.*
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundSeatAssignmentPacketHandler
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
@@ -62,14 +49,7 @@ import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
import com.cobblemon.mod.common.client.net.storage.pc.*
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.client.net.trade.*
import com.cobblemon.mod.common.net.PacketRegisterInfo
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
@@ -85,30 +65,19 @@ import com.cobblemon.mod.common.net.messages.client.data.*
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.net.messages.client.effect.SaccharineLogBlockParticlesPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.*
import com.cobblemon.mod.common.net.messages.client.habitat.OpenHabitatBlockEditorPacket
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
import com.cobblemon.mod.common.net.messages.client.pasture.*
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClientboundSeatAssignmentPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.AddFormPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.ClearFormsPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.form.RemoveFormPacket
import com.cobblemon.mod.common.net.messages.client.settings.OpenCobblemonConfigScreenPacket
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
@@ -123,45 +92,17 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.RenamePCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
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
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SetActiveTMPacket
import com.cobblemon.mod.common.net.messages.client.ui.SetTMMachineContainerDataPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.client.trade.*
import com.cobblemon.mod.common.net.messages.client.ui.*
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.*
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
@@ -188,14 +129,8 @@ import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPack
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.*
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.form.AcceptFormPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.form.RevertFormPacket
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdatePassengerPositionPacket
@@ -207,23 +142,12 @@ import com.cobblemon.mod.common.net.messages.server.storage.party.PartyTutorialP
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.AcceptFormHandler
import com.cobblemon.mod.common.net.messages.server.trade.*
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.RevertFormHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
import com.cobblemon.mod.common.net.serverhandling.UsePokeSkillHandler
import com.cobblemon.mod.common.net.serverhandling.battle.*
import com.cobblemon.mod.common.net.serverhandling.behaviour.DamageOnCollisionPacketHandler
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
@@ -251,11 +175,7 @@ import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandl
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.*
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdatePassengerPositionHandler
@@ -271,12 +191,7 @@ import com.cobblemon.mod.common.net.serverhandling.storage.party.PartyTutorialPa
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.net.serverhandling.trade.*
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerPlayer
@@ -346,6 +261,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RideBoostsUpdatePacket.ID, RideBoostsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RideStaminaUpdatePacket.ID, RideStaminaUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(SkillCooldownsUpdatePacket.ID, SkillCooldownsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(AlphaUpdatePacket.ID, AlphaUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(ScaleModifierUpdatePacket.ID, ScaleModifierUpdatePacket::decode, PokemonUpdatePacketHandler()))
@@ -446,6 +362,8 @@ 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(PokeSkillsRegistrySyncPacket.ID, PokeSkillsRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -508,11 +426,6 @@ object CobblemonNetwork {
// Pokédex scanning
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
// Form packets
list.add(PacketRegisterInfo(AddFormPacket.ID, AddFormPacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(ClearFormsPacket.ID, ClearFormsPacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RemoveFormPacket.ID, RemoveFormPacket::decode, PokemonUpdatePacketHandler()))
// Riding
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
list.add(PacketRegisterInfo(ClientboundUpdateDriverInputPacket.ID, ClientboundUpdateDriverInputPacket::decode, ClientboundUpdateDriverInputHandler))
@@ -542,6 +455,7 @@ object CobblemonNetwork {
// Interaction Packets
list.add(PacketRegisterInfo(InteractPokemonPacket.ID, InteractPokemonPacket::decode, InteractPokemonHandler))
list.add(PacketRegisterInfo(RequestPlayerInteractionsPacket.ID, RequestPlayerInteractionsPacket::decode, RequestInteractionsHandler))
list.add(PacketRegisterInfo(UsePokeSkillPacket.ID, UsePokeSkillPacket::decode, UsePokeSkillHandler))
// Storage Packets
list.add(PacketRegisterInfo(SendOutPokemonPacket.ID, SendOutPokemonPacket::decode, SendOutPokemonHandler))
@@ -628,10 +542,6 @@ object CobblemonNetwork {
// NPC packets
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
// Form Packets
list.add(PacketRegisterInfo(AcceptFormPacket.ID, AcceptFormPacket::decode, AcceptFormHandler))
list.add(PacketRegisterInfo(RevertFormPacket.ID, RevertFormPacket::decode, RevertFormHandler))
// Riding packet(s)
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, ServerboundUpdateOrientationHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.entity.pokemon.PokeSkill
import com.cobblemon.mod.common.net.messages.client.data.PokeSkillsRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.adapters.ActionEffectTimelineAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.TextAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.entity.player.Player
/**
* The JSON data registry for all the possible [PokeSkill]s.
*
* @author Hiroku
* @since August 31st, 2025
*/
object CobblemonPokeSkills : JsonDataRegistry<PokeSkill> {
override val id = cobblemonResource("poke_skills")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<CobblemonPokeSkills>()
override val typeToken = TypeToken.get(PokeSkill::class.java)
override val resourcePath = "poke_skills"
override val gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(ActionEffectTimeline::class.java, ActionEffectTimelineAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(Component::class.java, TextAdapter)
.create()
var skills = mapOf<ResourceLocation, PokeSkill>()
fun getAccessibleSkills(player: Player, pokemon: Pokemon): List<PokeSkill> {
return skills.values.filter { it.canAccess(player, pokemon) }
}
override fun reload(data: Map<ResourceLocation, PokeSkill>) {
data.forEach { (id, skill) -> skill.id = id }
skills = data
observable.emit(this)
Cobblemon.LOGGER.info("Loaded ${skills.size} PokéSkills")
}
override fun sync(player: ServerPlayer) {
player.sendPacket(PokeSkillsRegistrySyncPacket(skills.values.toList()))
}
}
@@ -9,9 +9,9 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.*
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
import java.util.function.Supplier
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.ai.sensing.Sensor
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common
import java.util.Optional
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.Entity
@@ -19,6 +18,7 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.trading.ItemCost
import net.minecraft.world.item.trading.MerchantOffer
import java.util.Optional
/**
* A generator for various trade offers in the mod.
@@ -11,10 +11,10 @@ package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import java.util.Optional
class AspectCriterion(
playerCtx: Optional<ContextAwarePredicate>,
@@ -14,8 +14,8 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
class CastPokeRodContext(val baitId: ResourceLocation)
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.advancement.criterion
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import java.util.Optional
/**
* A context that is used when you require a [CountableContext] along with some type string.
@@ -14,8 +14,8 @@ import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceLocation)
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import com.cobblemon.mod.common.util.codec.CodecUtils
import com.google.gson.JsonObject
import com.mojang.serialization.Codec
@@ -26,7 +25,7 @@ class AbilityTemplate(
var builder: (AbilityTemplate, forced: Boolean, priority: Priority) -> Ability = { template, forced, priority -> Ability(template, forced, priority) },
val displayName: String = "cobblemon.ability.$name",
val description: String = "cobblemon.ability.$name.desc"
) : ShowdownIdentifiable {
) {
/**
* Returns the Ability or if applicable the extension connected to this template
*/
@@ -46,8 +45,6 @@ class AbilityTemplate(
*/
fun create(json: JsonObject) = create().loadFromJSON(json)
override fun showdownId(): String = ShowdownIdentifiable.REGEX.replace(this.name.lowercase(), "")
companion object {
@JvmStatic
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.util.activityRegistry
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.withQueryValue
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
import kotlin.math.sqrt
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.PathfinderMob
/**
* Used to maintain some settings around how the entity should wander this tick. The idea is you
@@ -8,12 +8,16 @@
package com.cobblemon.mod.common.api.ai.config
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
@@ -11,8 +11,13 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.weightedSelection
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -8,10 +8,12 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask.Companion.wrapped
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.mainThreadRuntime
import com.cobblemon.mod.common.util.resolveBoolean
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.StopBeingAngryIfTargetDead
@@ -9,7 +9,9 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.Difficulty
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.SwitchToBattleTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class SwitchToNPCBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -25,6 +25,7 @@ import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.sensing.SensorType
/**
@@ -22,7 +22,6 @@ import com.cobblemon.mod.common.util.mainThreadRuntime
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import kotlin.math.ceil
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
@@ -35,6 +34,7 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.level.material.Fluids
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.phys.Vec3
import kotlin.math.ceil
class WaterWanderTaskConfig : SingleTaskConfig {
val condition = booleanVariable(WANDER, "water_wanders", true).asExpressible()
@@ -54,9 +54,9 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
import com.cobblemon.mod.common.pokemon.transformation.progress.DefeatTransformationProgress
import com.cobblemon.mod.common.pokemon.transformation.progress.LastBattleCriticalHitsTransformationProgress
import com.cobblemon.mod.common.pokemon.transformation.requirements.DefeatRequirement
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
import com.cobblemon.mod.common.pokemon.requirements.DefeatRequirement
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getPlayer
import com.cobblemon.mod.common.util.giveOrDropItemStack
@@ -97,8 +97,8 @@ open class PokemonBattle(
this.actors.forEach { actor ->
actor.battle = this
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.effectedPokemon.requirementProgress
.filterIsInstance<LastBattleCriticalHitsTransformationProgress>()
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
.forEach { it.reset() }
}
}
@@ -271,13 +271,12 @@ open class PokemonBattle(
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
val pokemon = opponentPokemon.effectedPokemon
if (facedFainted) {
if (pokemon.hasMatchingRequirement<DefeatRequirement>({ it.target.matches(faintedPokemon.effectedPokemon) })) {
val requiredPokemonProperties = pokemon.getRelevantRequirements<DefeatRequirement> { it.target.matches(faintedPokemon.effectedPokemon) }
.map { it.target }
.distinctBy { it.asString() }
for (props in requiredPokemonProperties) {
val progress = pokemon.progressFirstOrCreate({ it is DefeatTransformationProgress && it.currentProgress().target.asString().equals(props.asString(), ignoreCase = true) }, ::DefeatTransformationProgress)
progress.updateProgress(DefeatTransformationProgress.Progress(props.copy(), progress.currentProgress().amount + 1))
pokemon.lockedEvolutions.forEach { evolution ->
evolution.requirements.filterIsInstance<DefeatRequirement>().forEach { defeatRequirement ->
if (defeatRequirement.target.matches(faintedPokemon.effectedPokemon)) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatEvolutionProgress() }
progress.updateProgress(DefeatEvolutionProgress.Progress(defeatRequirement.target, progress.currentProgress().amount + 1))
}
}
}
}
@@ -22,9 +22,9 @@ import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.net.messages.client.battle.BattleApplyPassResponsePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import java.util.UUID
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import java.util.UUID
import net.minecraft.server.level.ServerPlayer
abstract class BattleActor(
@@ -21,7 +21,6 @@ import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.awt.Color
import net.minecraft.advancements.critereon.MinMaxBounds
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
@@ -31,6 +30,7 @@ import net.minecraft.tags.TagKey
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.awt.Color
/**
* The data registry for [Berry].
@@ -26,10 +26,10 @@ import com.cobblemon.mod.common.util.writeBox
import com.cobblemon.mod.common.util.writeEnumConstant
import com.cobblemon.mod.common.util.writeIdentifier
import com.google.gson.annotations.SerializedName
import java.awt.Color
import java.util.EnumSet
import net.minecraft.core.BlockPos
import net.minecraft.network.RegistryFriendlyByteBuf
import java.awt.Color
import java.util.EnumSet
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.world.entity.LivingEntity
@@ -8,11 +8,11 @@
package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
class EvolutionItemDropEntry : ItemDropEntry() {
val requirements: MutableSet<TransformationRequirement> = mutableSetOf()
val requirements: MutableSet<Requirement> = mutableSetOf()
override fun canDrop(pokemon: Pokemon?): Boolean = pokemon != null && requirements.all { it.check(pokemon) }
}
@@ -48,10 +48,6 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionAcceptedEv
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
import com.cobblemon.mod.common.api.events.pokemon.form.FormAcceptedEvent
import com.cobblemon.mod.common.api.events.pokemon.form.FormCompleteEvent
import com.cobblemon.mod.common.api.events.pokemon.form.FormDisplayEvent
import com.cobblemon.mod.common.api.events.pokemon.form.FormTestedEvent
import com.cobblemon.mod.common.api.events.pokemon.healing.PokemonHealedEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
@@ -107,18 +103,6 @@ object CobblemonEvents {
@JvmField
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
@JvmField
val FORM_ACCEPTED = CancelableObservable<FormAcceptedEvent>()
@JvmField
val FORM_DISPLAY = EventObservable<FormDisplayEvent>()
@JvmField
val FORM_TESTED = EventObservable<FormTestedEvent>()
@JvmField
val FORM_COMPLETE = EventObservable<FormCompleteEvent>()
@JvmField
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
@@ -15,7 +15,9 @@ import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
import com.cobblemon.mod.common.util.asArrayValue
import net.minecraft.world.entity.LivingEntity
@@ -12,6 +12,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue
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.moLangFunctionMap
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.trade.TradeParticipant
import com.cobblemon.mod.common.util.getPlayer
@@ -12,8 +12,8 @@ import com.bedrockk.molang.runtime.value.MoValue
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.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
/**
* Fired when an evolution is accepted.
@@ -10,8 +10,8 @@ package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
/**
* Fired after an evolution finishes.
@@ -8,9 +8,9 @@
package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.EvolutionDisplay
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.evolution.EvolutionDisplay
/**
* Fired before an evolution is sent to clients.
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.api.events.pokemon.evolution
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
/**
@@ -12,8 +12,8 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.util.getBoolean
/**
@@ -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.events.pokemon.form
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
/**
* Fired when a temporary form change is accepted.
* Cancelling will not notify users nor remove the form from the pending list.
*
* @param pokemon The [Pokemon] about to change form.
* @param form The [TemporaryForm] being used.
*
* @author Hiroku
* @since June 3rd, 2026
*/
data class FormAcceptedEvent(
override val pokemon: Pokemon,
override val form: TemporaryForm
) : Cancelable(), FormEvent {
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"form" to StringValue(form.formOnlyShowdownId())
)
val functions = moLangFunctionMap(cancelFunc)
}
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.pokemon.form
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
/**
* Fired after a temporary form change finishes.
*
* @param pokemon The [Pokemon] resulting from the form change.
* @param form The [TemporaryForm] that was used.
*
* @author Hiroku
* @since June 3rd, 2026
*/
data class FormCompleteEvent(
/** The [Pokemon] that did the form change. */
override val pokemon: Pokemon,
/** The [TemporaryForm] that was used. */
override val form: TemporaryForm
) : FormEvent {
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"form" to StringValue(form.formOnlyShowdownId())
)
}
@@ -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.events.pokemon.form
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.FormDisplay
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
/**
* Fired before a form is sent to clients. For modifications on the actual output when they accept it modify
* the [display] directly.
*
* @param pokemon The [Pokemon] that will change form if this proposition is accepted.
* @param display The current [FormDisplay] the client will see.
* @param form The [TemporaryForm] being used.
*
* @author Hiroku
* @since June 3rd, 2026
*/
data class FormDisplayEvent(
override val pokemon: Pokemon,
var display: FormDisplay,
override val form: TemporaryForm
) : FormEvent {
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"display" to display.struct,
"form" to StringValue(form.formOnlyShowdownId())
)
}
@@ -1,22 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.pokemon.form
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
/**
* The root of the various [TemporaryForm]-related events.
*/
interface FormEvent {
/** The Pokémon impacted in this event.*/
val pokemon: Pokemon
/*** The form triggering this event.*/
val form: TemporaryForm
}
@@ -1,47 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.pokemon.form
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
import com.cobblemon.mod.common.util.getBoolean
/**
* An event fired when [TemporaryForm.test] has been performed.
* The final state [result] will be the return value of the test function.
*
* @property pokemon The [Pokemon] being tested against.
* @property form The [TemporaryForm] instance performing the test.
* @property originalResult The base result from the Cobblemon implementation.
* @property result The final value returned by [TemporaryForm.test].
*/
data class FormTestedEvent(
override val pokemon: Pokemon,
override val form: TemporaryForm,
val originalResult: Boolean,
) : FormEvent {
var result: Boolean = originalResult
val context = mutableMapOf(
"pokemon" to pokemon.struct,
"form" to StringValue(form.formOnlyShowdownId()),
"original_result" to DoubleValue(originalResult),
)
val functions = moLangFunctionMap(
"result" to { DoubleValue(result) },
"set_result" to {
result = it.getBoolean(0)
DoubleValue.ONE
}
)
}
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.getPlayer
import net.minecraft.server.level.ServerPlayer
/**
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.events.storage
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
@@ -16,7 +16,9 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.api.storage.PokemonStore
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.getPlayer
import net.minecraft.server.level.ServerPlayer
import java.util.UUID
/**
* The base of the events around the release of Pokémon from pc or party.
@@ -14,7 +14,7 @@ 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.net.messages.client.data.FossilRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.transformation.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
@@ -13,13 +13,13 @@ import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.data.PokemonInteractionsSyncPacket
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.transformation.requirements.PokemonPropertiesRequirement
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.requirements.PokemonPropertiesRequirement
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
@@ -46,7 +46,7 @@ object PokemonInteractions : JsonDataRegistry<PokemonInteractionSet> {
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
.registerTypeAdapter(TransformationRequirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(InteractionEffect::class.java, InteractionEffectAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
@@ -12,16 +12,11 @@ import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.giveOrDropItemStack
import com.cobblemon.mod.common.util.readExpressionLike
import com.cobblemon.mod.common.util.withPlayerValue
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.util.writeExpressionLike
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.util.*
import com.google.gson.annotations.SerializedName
import net.minecraft.core.registries.Registries
import net.minecraft.network.FriendlyByteBuf
@@ -34,7 +29,7 @@ import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.ItemStack
data class PokemonInteractionSet(
val requirements: List<TransformationRequirement> = listOf(),
val requirements: List<Requirement> = listOf(),
val interactions: List<PokemonInteraction> = listOf(),
) {
fun encode(buffer: FriendlyByteBuf) {
@@ -56,7 +51,7 @@ data class PokemonInteractionSet(
}
data class PokemonInteraction(
val requirements: List<TransformationRequirement> = listOf(),
val requirements: List<Requirement> = listOf(),
val effects: List<InteractionEffect> = listOf(),
val cooldown: ExpressionLike = "0".asExpressionLike()
) {
@@ -74,7 +74,7 @@ abstract class RequestManager<T : ServerPlayerActionRequest> {
?: this.getInboundRequest(receiver.uuid, requestID)
/** Determines whether [player] can receive a [T]. */
open fun isBusy(player: ServerPlayer): Boolean = player.isBusy() || player.isPartyBusy()
open fun isBusy(player: ServerPlayer): Boolean = player.isInBattle() || player.isTrading() || player.party().find { it.entity?.isBusy == true } != null
/** Determines if the [target] is a valid interaction request target. */
abstract fun isValidInteraction(player: ServerPlayer, target: ServerPlayer): Boolean
@@ -21,9 +21,34 @@ import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.molang.function.*
import com.cobblemon.mod.common.api.molang.function.BattleActorMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.BattleMessageMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.BattleMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.BiomeMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.BlockMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.DimensionTypeMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.DropEntryMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.EntityMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.EvolutionMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.GeneralMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.ItemStackMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.LivingEntityMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.NPCMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PCMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PartyMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PlayerMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokedexMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonEntityMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonPropertiesMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.PokemonStoreMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.ServerMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.SpawnablePositionMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.SpeciesMoLangFunctions
import com.cobblemon.mod.common.api.molang.function.WorldMoLangFunctions
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.storage.PokemonStore
@@ -33,10 +58,8 @@ import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.util.effectiveName
import com.mojang.datafixers.util.Either
import java.util.function.Function
import net.minecraft.core.Holder
import net.minecraft.core.Registry
import net.minecraft.core.RegistryAccess
@@ -60,7 +83,14 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.dimension.DimensionType
import net.minecraft.world.level.levelgen.Heightmap
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.util.function.Function
/**
* Holds a bunch of useful MoLang trickery that can be used or extended in API
@@ -263,11 +293,11 @@ object MoLangFunctions {
)
value.functions["is_in"] = Function put@{ params: MoParams ->
val tag = TagKey.create(key, ResourceLocation.parse(params.getString(0).replace("#", "")))
return@put DoubleValue(if (value.obj.`is`(tag)) 1.0 else 0.0)
return@put DoubleValue(value.obj.`is`(tag))
}
value.functions["is_of"] = Function put@{ params: MoParams ->
val identifier = ResourceLocation.parse(params.getString(0))
return@put DoubleValue(if (value.obj.`is`(identifier)) 1.0 else 0.0)
return@put DoubleValue(value.obj.`is`(identifier))
}
return value
}
@@ -13,7 +13,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.util.asArrayValue
import java.util.UUID
import java.util.*
object BattleMoLangFunctions : AbstractMoLangFunctionHolder<PokemonBattle>() {
override fun PokemonBattle.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
@@ -25,7 +25,7 @@ object DropEntryMoLangFunctions : AbstractMoLangFunctionHolder<DropEntry>() {
map["max_selectable_times"] = { DoubleValue(drop.maxSelectableTimes.toDouble()) }
map["can_drop"] = { params ->
val pokemon = params.getOrNull<ObjectValue<Pokemon>>(0)?.obj
DoubleValue(if (drop.canDrop(pokemon)) 1.0 else 0.0)
DoubleValue(drop.canDrop(pokemon))
}
return map
}
@@ -35,12 +35,14 @@ import com.cobblemon.mod.common.util.effectiveName
import com.cobblemon.mod.common.util.getBlockStatesWithPos
import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
import com.cobblemon.mod.common.util.getIntOrNull
import com.cobblemon.mod.common.util.getIsSubmerged
import com.cobblemon.mod.common.util.getOrNull
import com.cobblemon.mod.common.util.getStringOrNull
import com.cobblemon.mod.common.util.isStandingOn
import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.worldRegistry
import net.minecraft.core.BlockPos
import net.minecraft.core.registries.Registries
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
@@ -48,7 +50,10 @@ import net.minecraft.tags.TagKey
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.damagesource.DamageTypes
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.level.block.BonemealableBlock
import net.minecraft.world.level.block.CropBlock
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.util.UUID
@@ -78,8 +83,13 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
"vertical_velocity" to { DoubleValue(thisEntity.deltaMovement.y) },
"is_on_ground" to { _ -> DoubleValue(thisEntity.onGround()) },
"world" to { _ -> thisEntity.level().worldRegistry.wrapAsHolder(thisEntity.level()).asWorldMoLangValue() },
"dimension" to { StringValue(thisEntity.level().dimension().location().toString()) },
"biome" to { _ -> thisEntity.level().getBiome(thisEntity.blockPosition()).asBiomeMoLangValue() },
"is_passenger" to { DoubleValue(thisEntity.isPassenger) },
"is_passenger" to isPassenger@{ params ->
val passengerEntity = (params.get<MoValue>(0) as? ObjectValue<*>)?.obj as? LivingEntity ?: return@isPassenger DoubleValue.ZERO
DoubleValue(passengerEntity in thisEntity.passengers)
},
"discard" to { thisEntity.discard() },
"is_sneaking" to { _ -> DoubleValue(thisEntity.isShiftKeyDown) },
"is_sprinting" to { _ -> DoubleValue(thisEntity.isSprinting) },
@@ -121,6 +131,62 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
listOf(thisEntity.deltaMovement.x, thisEntity.deltaMovement.y, thisEntity.deltaMovement.z)
.asArrayValue(::DoubleValue)
},
"set_position" to { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
thisEntity.setPos(x, y, z)
DoubleValue.ONE
},
"fertilize_nearby_crops" to { params -> //TODO: pretty bespoke. Maybe should be moved or generalized?
val radius = params.getIntOrNull(0) ?: 8
val maxCrops = params.getIntOrNull(1) ?: 8
var fertilizedCount = 0
val level = thisEntity.level()
val centerPos = thisEntity.blockPosition()
// Find all bonemealable blocks within radius
val bonemealableBlocks = mutableListOf<BlockPos>()
for (x in -radius..radius) {
for (y in -3..3) { // Limited vertical range
for (z in -radius..radius) {
val pos = centerPos.offset(x, y, z)
val blockState = level.getBlockState(pos)
val block = blockState.block
// Check if block can be bonemealed
if (block is BonemealableBlock && block is CropBlock && block.isValidBonemealTarget(level, pos, blockState)) {
bonemealableBlocks.add(pos)
}
}
}
}
// Shuffle and take up to maxCrops blocks to fertilize
bonemealableBlocks.shuffle()
val blocksToFertilize = bonemealableBlocks.take(maxCrops)
for (pos in blocksToFertilize) {
val blockState = level.getBlockState(pos)
val block = blockState.block
if (block is BonemealableBlock && block.isValidBonemealTarget(level, pos, blockState)) {
if (block.isBonemealSuccess(level, level.random, pos, blockState)) {
block.performBonemeal(level as ServerLevel, level.random, pos, blockState)
// Add bonemeal particle
val particlePos = block.getParticlePos(pos)
level.levelEvent(1505, particlePos, 15) // Same event used for bonemealing in vanilla
fertilizedCount++
}
}
}
DoubleValue(fertilizedCount.toDouble())
},
"tags" to {
val tags = thisEntity.tags
val array = ArrayStruct(hashMapOf())
@@ -233,7 +299,7 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
val intangible = params.getBooleanOrNull(0) ?: true
thisEntity.noPhysics = intangible
DoubleValue.ONE
}
},
)
@@ -11,34 +11,31 @@ package com.cobblemon.mod.common.api.molang.function
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokemon.transformation.Transformation
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.pokemon.transformation.triggers.ItemInteractionTrigger
import com.cobblemon.mod.common.pokemon.transformation.triggers.LevelUpTrigger
import com.cobblemon.mod.common.pokemon.transformation.triggers.TradeTrigger
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
object EvolutionMoLangFunctions : AbstractMoLangFunctionHolder<Transformation>() {
override fun Transformation.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
object EvolutionMoLangFunctions : AbstractMoLangFunctionHolder<Evolution>() {
override fun Evolution.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
val evolution = this
val map = hashMapOf<String, (MoParams) -> Any>()
map["result"] = { evolution.result.asMoLangValue() }
map["is_optional"] = { DoubleValue(evolution.optional) }
map["reevaluate"] = { DoubleValue(evolution.reevaluate) }
map["consumes_held_item"] = { DoubleValue(evolution.consumeHeldItem) }
if (evolution is Evolution) {
map["result"] = { evolution.result.asMoLangValue() }
when (evolution.trigger) {
is LevelUpTrigger -> {
map["is_level_up"] = { DoubleValue.ONE }
}
when (evolution) {
is LevelUpEvolution -> {
map["is_level_up"] = { DoubleValue.ONE }
}
is TradeTrigger -> {
map["is_trade"] = { DoubleValue.ONE }
}
is TradeEvolution -> {
map["is_trade"] = { DoubleValue.ONE }
}
is ItemInteractionTrigger -> {
map["is_item"] = { DoubleValue.ONE }
}
is ItemInteractionEvolution -> {
map["is_item"] = { DoubleValue.ONE }
}
}
@@ -39,6 +39,7 @@ import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.behavior.EntityTracker
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.memory.WalkTarget
@@ -123,6 +124,23 @@ object LivingEntityMoLangFunctions : AbstractMoLangFunctionHolder<LivingEntity>(
duration.toLong()
)
}
map["look_at_entity"] = put@{ params ->
val targetEntity = params.get<MoValue>(0)
val duration = params.getDoubleOrNull(1)?.toInt() ?: 20
val lookEntity = if (targetEntity is ObjectValue<*> && targetEntity.obj is Entity) {
targetEntity.obj as Entity
} else {
return@put DoubleValue.ZERO
}
// Set the current entity to track the looked for entity
val brain = entity.brain
val tracker = EntityTracker(lookEntity, true)
brain.setMemoryWithExpiry(MemoryModuleType.LOOK_TARGET, tracker, duration.toLong())
DoubleValue.ONE
}
map["get_wander_control_memory"] = put@{
val value = entity.brain.getMemorySafely(CobblemonMemories.WANDER_CONTROL).orElse(null)
?: CobblemonWanderControl()
@@ -23,6 +23,7 @@ import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
@@ -32,6 +33,7 @@ import com.cobblemon.mod.common.util.activeDialogue
import com.cobblemon.mod.common.util.asBlockPos
import com.cobblemon.mod.common.util.asResource
import com.cobblemon.mod.common.util.asUUID
import com.cobblemon.mod.common.util.blockRegistry
import com.cobblemon.mod.common.util.getBattleState
import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
@@ -44,14 +46,19 @@ import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.pc
import com.cobblemon.mod.common.util.pokedex
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.util.toArrayStruct
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.ClipContext
import net.minecraft.world.level.GameType
import net.minecraft.world.phys.HitResult
import kotlin.collections.iterator
object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
@@ -379,6 +386,61 @@ object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
} ?: DoubleValue.ZERO
}
map["has_chosen_starter"] = { _ -> DoubleValue(Cobblemon.playerDataManager.getGenericData(player).starterSelected) }
map["ride"] = put@{ params ->
val entity = (params.get<MoValue>(0) as? ObjectValue<*>)?.obj as? Entity ?: return@put DoubleValue.ZERO
player.startRiding(entity)
}
map["has_respawn_position"] = {
DoubleValue(player.respawnPosition != null)
}
map["respawn_position"] = {
player.respawnPosition?.toArrayStruct() ?: DoubleValue.ZERO
}
map["respawn_dimension"] = {
StringValue(player.respawnDimension.location().toString())
}
map["teleport_to_respawn"] = put@{
val respawnPosition = player.respawnPosition?.center ?: return@put DoubleValue.ZERO
player.teleportTo(respawnPosition.x, respawnPosition.y, respawnPosition.z)
DoubleValue.ONE
}
map["get_looked_block"] = put@{ params ->
// Get the block the player is looking at 'distance' units away
val distance = params.getDoubleOrNull(0) ?: 8.0
// perform clip
val level = player.level()
val eye = player.eyePosition
val view = player.getViewVector(1.0f)
val lookPos = eye.add(view.scale(distance))
val hitResult = level.clip(ClipContext(eye, lookPos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player))
if (hitResult.type == HitResult.Type.BLOCK) {
// Get base block info
val blockPos = hitResult.blockPos
val blockState = level.getBlockState(blockPos)
val blockHolder = level.blockRegistry.wrapAsHolder(blockState.block)
val blockValue = blockHolder.asMoLangValue(Registries.BLOCK)
// Attach the position to the blockValue return
blockValue.addFunction("x") { DoubleValue(blockPos.x.toDouble()) }
blockValue.addFunction("y") { DoubleValue(blockPos.y.toDouble()) }
blockValue.addFunction("z") { DoubleValue(blockPos.z.toDouble()) }
return@put blockValue
} else {
return@put DoubleValue.ZERO
}
}
map["is_battling"] = {
DoubleValue(player.isInBattle())
}
}
if (player is AbstractClientPlayer) {
map["is_battling"] = {
DoubleValue(CobblemonClient.battle?.spectating == false) // Checks not-null and not-spectating at the same time, trust
}
}
return map
@@ -15,6 +15,7 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonMovesetBuilders
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.api.mark.Marks
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.moves.BenchedMove
@@ -26,6 +27,9 @@ import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.pokemon.IVs
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ActivePokemonState
import com.cobblemon.mod.common.pokemon.activestate.SentOutState
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.getBooleanOrNull
@@ -109,7 +113,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())
@@ -444,9 +448,32 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
map["force_evolve"] = forceEvolve@{ params ->
val idx = params.getInt(0)
val evolution = if (idx >= 0) pokemon.evolutions.elementAtOrNull(idx) else return@forceEvolve DoubleValue.ZERO
evolution?.perform(pokemon)
evolution?.forceEvolve(pokemon)
StringValue(evolution.toString())
}
map["is_sent_out"] = {
DoubleValue(pokemon.state is SentOutState)
}
map["is_shouldered"] = {
DoubleValue(pokemon.state is ShoulderedState)
}
map["entity"] = {
(pokemon.state as? ActivePokemonState)?.entity?.struct ?: DoubleValue.ZERO
}
map["is_rideable"] = put@{
return@put DoubleValue(!pokemon.riding.behaviours.isNullOrEmpty())
}
map["has_status"] = put@{ params ->
val status = params.getString(0).asIdentifierDefaultingNamespace()
return@put DoubleValue(pokemon.status?.status?.name == status)
}
map["add_skill_cooldown"] = put@{ params ->
val skillId = params.getString(0).asIdentifierDefaultingNamespace()
val cooldownTicks = params.getIntOrNull(1)
val skill = CobblemonPokeSkills.skills[skillId] ?: return@put DoubleValue.ZERO
pokemon.addSkillCooldown(skillId, cooldownTicks ?: skill.cooldownTicks)
return@put DoubleValue.ONE
}
map["entity"] = { pokemon.entity?.asMoLangValue() ?: DoubleValue.ZERO }
map["is_alpha"] = { DoubleValue(pokemon.isAlpha) }
@@ -40,6 +40,7 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.Level.ExplosionInteraction
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity
import net.minecraft.world.level.levelgen.Heightmap
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
@@ -61,6 +62,26 @@ object WorldMoLangFunctions : AbstractMoLangFunctionHolder<Holder<Level>>() {
val time = world.dayTime % 24000
return@put DoubleValue(timeOfDay.contains(time.toInt()))
}
map["add_furnace_fuel"] = put@{ params ->
val x = params.getInt(0)
val y = params.getInt(1)
val z = params.getInt(2)
val fuelTicks = params.getInt(3)
val blockEntity = world.getBlockEntity(BlockPos(x, y, z))
if (blockEntity is AbstractFurnaceBlockEntity) {
// Add fuel time to the furnace
blockEntity.litTime += fuelTicks
// If this exceeds the litDuration then bump it up
if (blockEntity.litTime >= blockEntity.litDuration) {
blockEntity.litDuration = blockEntity.litTime
}
blockEntity.setChanged()
return@put DoubleValue.ONE
}
return@put DoubleValue.ZERO
}
map["game_time"] = { _ -> DoubleValue(world.gameTime.toDouble()) }
map["time_of_day"] = put@{
val time = world.dayTime % 24000
@@ -128,13 +149,13 @@ object WorldMoLangFunctions : AbstractMoLangFunctionHolder<Holder<Level>>() {
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
val range = params.getDouble(3).toFloat()
val range = params.getDoubleOrNull(3) ?: 8.0
world.explode(
null,
x,
y,
z,
range,
range.toFloat(),
ExplosionInteraction.valueOf(
params.getStringOrNull(4)?.uppercase() ?: ExplosionInteraction.TNT.name
)
@@ -12,8 +12,6 @@ import com.bedrockk.molang.runtime.struct.MoStruct
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
import com.cobblemon.mod.common.api.types.ElementalType
@@ -57,7 +55,7 @@ open class MoveTemplate(
val critRatio: Double,
val effectChances: Array<Double>,
val weight: Float
) : ShowdownIdentifiable {
) {
val struct: MoStruct by lazy {
QueryStruct(hashMapOf())
.addFunction("name") { StringValue(name) }
@@ -165,8 +163,6 @@ open class MoveTemplate(
return this.elementalType
}
override fun showdownId() = ShowdownIdentifiable.REGEX.replace(this.name.lowercase(), "")
fun getSelectionWeight(form: FormData): Float {
return if (this in form.signatureMoves) {
weight * MovesetBuilder.signatureMoveWeightMultiplier
@@ -10,17 +10,13 @@ package com.cobblemon.mod.common.api.moves.animations
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
import com.cobblemon.mod.common.api.scheduling.Schedulable
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import java.util.concurrent.CompletableFuture
import net.minecraft.world.entity.Entity
import net.minecraft.world.level.Level
import java.util.concurrent.CompletableFuture
/**
* An action effect will run and execute a series of 'keyframes', with each running once
@@ -40,7 +36,7 @@ class ActionEffectTimeline(
}
fun run(context: ActionEffectContext): CompletableFuture<Unit> {
val future = if (timeline.isEmpty() || !context.runtime.resolveBoolean(condition)) {
return if (timeline.isEmpty() || !context.runtime.resolveBoolean(condition)) {
CompletableFuture.completedFuture(Unit)
} else {
val finalFuture = CompletableFuture<Unit>()
@@ -51,14 +47,10 @@ class ActionEffectTimeline(
it.printStackTrace()
CompletableFuture.completedFuture(Unit)
}
context.future = future
future.thenRun { context.getHolds().forEach(context::removeHold) }
return future
}
fun chainKeyframes(context: ActionEffectContext, iterator: Iterator<ActionEffectKeyframe>, finalFuture: CompletableFuture<Unit>) {
if (!iterator.hasNext()) {
if (!iterator.hasNext() || context.cancelled) {
finalFuture.complete(Unit)
} else {
val keyframe = iterator.next()
@@ -73,45 +65,16 @@ class ActionEffectTimeline(
class ActionEffectContext(
val actionEffect: ActionEffectTimeline,
private val holds: MutableSet<String> = mutableSetOf(),
val holds: MutableSet<String> = mutableSetOf(),
val providers: MutableList<Any> = mutableListOf(),
val runtime: MoLangRuntime,
var canBeInterrupted: Boolean = false,
var interrupted: Boolean = false,
var cancelled: Boolean = false,
var currentKeyframes: MutableList<ActionEffectKeyframe> = mutableListOf(),
var level: Level? = null,
var holdRemovalCallbacks: MutableMap<String, () -> Unit> = mutableMapOf(),
var tracker: Schedulable = ServerTaskTracker
var level: Level? = null
) {
companion object {
fun fromPokemonEntity(
actionEffect: ActionEffectTimeline,
pokemonEntity: PokemonEntity,
runtime: MoLangRuntime = MoLangRuntime().also { it.environment.query.addStandardFunctions() },
holds: Collection<String> = emptySet(),
holdRemovalCallbacks: Map<String, () -> Unit> = emptyMap()
): ActionEffectContext {
return ActionEffectContext(
actionEffect = actionEffect,
providers = mutableListOf(UsersProvider(listOf(pokemonEntity))),
holdRemovalCallbacks = holdRemovalCallbacks.toMutableMap(),
holds = holds.toMutableSet(),
runtime = runtime,
level = pokemonEntity.level()
)
}
}
lateinit var future: CompletableFuture<Unit>
inline fun <reified T> findOneProvider() = providers.filterIsInstance<T>().firstOrNull()
/** Returns a reference to the internal holds set so you can keep an eye on it. */
fun getHolds(): Set<String> = holds
fun addHold(hold: String) = holds.add(hold)
fun removeHold(hold: String) {
holds.remove(hold)
holdRemovalCallbacks.remove(hold)?.invoke()
}
}
class UsersProvider(users: List<Entity>): EntityProvider {
@@ -57,6 +57,7 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
ActionEffectKeyframe.register<RunActionEffectKeyframe>("run_action_effect")
ActionEffectKeyframe.register<EntityParticlesActionEffectKeyframe>("entity_particles")
ActionEffectKeyframe.register<EntitySoundActionEffectKeyframe>("entity_sound")
ActionEffectKeyframe.register<CancelActionEffectKeyframe>("cancel")
}
override val gson = GsonBuilder()
@@ -21,7 +21,7 @@ import java.util.concurrent.CompletableFuture
class AddHoldsActionEffectKeyframe : ActionEffectKeyframe {
val holds = mutableSetOf<String>()
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
holds.forEach(context::addHold)
context.holds.addAll(holds)
return CompletableFuture.completedFuture(Unit)
}
}
@@ -49,6 +49,6 @@ class AnimationActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityC
players.forEach { it.sendPacket(pkt) }
}
return delayedFuture(seconds = delay.resolveFloat(context.runtime), tracker = context.tracker)
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
}
}
@@ -0,0 +1,19 @@
/*
* 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.moves.animations.keyframes
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import java.util.concurrent.CompletableFuture
class CancelActionEffectKeyframe : ConditionalActionEffectKeyframe() {
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
context.cancelled = true
return CompletableFuture.completedFuture(Unit)
}
}
@@ -46,6 +46,6 @@ class EntityMoLangActionEffectKeyframe : ConditionalActionEffectKeyframe(), Enti
players.forEach { it.sendPacket(pkt) }
}
return delayedFuture(seconds = delay.resolveFloat(context.runtime), context.tracker)
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
}
}
@@ -18,8 +18,10 @@ import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.commands.arguments.EntityArgument.getPlayers
import java.util.concurrent.CompletableFuture
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.phys.Vec3
/**
* Spawns particles on the entity based on the given particle effect and locator.
@@ -64,20 +66,41 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
allEntities.any { player.distanceTo(it) <= visibilityRange }
}
// Try to resolve a world-position target from runtime variables
val runtimeTargetPosition: Vec3? = try {
val x = "v.target_x".asExpressionLike().resolveDouble(context.runtime)
val y = "v.target_y".asExpressionLike().resolveDouble(context.runtime)
val z = "v.target_z".asExpressionLike().resolveDouble(context.runtime)
if (x != 0.0 || y != 0.0 || z != 0.0) Vec3(x, y, z) else null
} catch (e: Exception) {
null
}
sourceEntities.filter { it is PosableEntity }.forEach { entity ->
if (targetLocators == null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators)
packet.sendToPlayers(players)
}
else {
// If target entities are specified, send the particle using entity locators/position.
// If there are no target entities then attempt to send to v.target world position or send without target.
if (targetEntities.isNotEmpty()) {
targetEntities.forEach { targetEntity ->
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id, targetLocators!!.toList())
if (targetLocators != null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id, targetLocators!!.toList())
packet.sendToPlayers(players)
} else {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id)
packet.sendToPlayers(players)
}
}
} else {
if (runtimeTargetPosition != null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetPosition = runtimeTargetPosition)
packet.sendToPlayers(players)
} else {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators)
packet.sendToPlayers(players)
}
}
}
return delayedFuture(seconds = delay.resolveFloat(context.runtime), context.tracker)
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
}
}
@@ -15,8 +15,8 @@ import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.scheduling.delayedFuture
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import java.util.concurrent.CompletableFuture
import net.minecraft.core.registries.Registries
import java.util.concurrent.CompletableFuture
/**
* An action effect keyframe that plays a positioned sound for all matching entities.
@@ -45,6 +45,6 @@ class EntitySoundActionEffectKeyframe : ConditionalActionEffectKeyframe(), Entit
entity.playSound(soundEvent, 1f, 1f)
}
return delayedFuture(seconds = delay.resolveFloat(context.runtime), context.tracker)
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
}
}
@@ -25,6 +25,6 @@ class MoLangActionEffectKeyframe : ActionEffectKeyframe {
val delay: ExpressionLike = "0".asExpressionLike()
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
expressions.resolve(context.runtime)
return delayedFuture(seconds = delay.resolveFloat(context.runtime), context.tracker)
return delayedFuture(seconds = delay.resolveFloat(context.runtime))
}
}
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.scheduling.afterOnServer
import com.cobblemon.mod.common.entity.ai.OmniPathNavigation.NavigationContext
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpressionLike
@@ -60,7 +61,7 @@ class MoveToTargetActionEffectKeyframe : ActionEffectKeyframe {
}
)
context.tracker.after(seconds = timeout.resolveFloat(context.runtime)) {
afterOnServer(seconds = timeout.resolveFloat(context.runtime)) {
if (!future.isDone && !timedOut) {
timedOut = true
timeoutEffect.run(context).thenApply { future.complete(Unit) }
@@ -14,5 +14,5 @@ import com.cobblemon.mod.common.util.asExpressionLike
class PauseActionEffectKeyframe : ConditionalActionEffectKeyframe() {
val pause = "1".asExpressionLike()
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime), context.tracker)
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime))
}
@@ -25,8 +25,11 @@ class RemoveHoldsActionEffectKeyframe : ActionEffectKeyframe {
val holds = mutableSetOf<String>()
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
return delayedFuture(seconds = delay).thenApply {
val holdsToRemove = if (holds.isEmpty()) context.getHolds() else holds
holdsToRemove.forEach(context::removeHold)
if (holds.isEmpty()) {
context.holds.clear()
} else {
context.holds.removeAll(holds)
}
}
}
}
@@ -13,12 +13,13 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.scheduling.after
import com.cobblemon.mod.common.entity.ai.OmniPathNavigation.NavigationContext
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpressionLike
import java.util.concurrent.CompletableFuture
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
import java.util.concurrent.CompletableFuture
class ReturnToPositionActionEffectKeyframe : ActionEffectKeyframe {
val speed = 1F
@@ -55,7 +56,7 @@ class ReturnToPositionActionEffectKeyframe : ActionEffectKeyframe {
}
)
context.tracker.after(seconds = timeout.resolveFloat(context.runtime)) {
after(seconds = timeout.resolveFloat(context.runtime)) {
if (!future.isDone && !timedOut) {
timedOut = true
timeoutEffect.run(context).thenApply { future.complete(Unit) }
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.moves.animations.keyframes
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import java.util.concurrent.CompletableFuture
@@ -18,16 +20,37 @@ import net.minecraft.resources.ResourceLocation
* effect is marked complete only when the action effect it runs is complete unless [waitForActionEffect] is
* false.
*
* If [expression] is set, it will be resolved at runtime to determine the action effect identifier.
* This allows dynamic delegation based on MoLang variables (e.g. v.granting_move).
* If [expression] is not set, the static [actionEffect] identifier is used instead.
*
* @author Hiroku
* @since January 21st, 2024
*/
class RunActionEffectKeyframe : ConditionalActionEffectKeyframe() {
val actionEffect: ResourceLocation? = null
val expression: ExpressionLike? = null
val waitForActionEffect = true
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
return if (actionEffect != null) {
ActionEffects.actionEffects[actionEffect]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
val effectId = if (expression != null) {
val resolved = expression.resolveString(context.runtime)
if (resolved == "0" || resolved.isBlank()) {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe expression resolved to empty/zero string: $resolved")
return skip()
}
try {
ResourceLocation.parse(resolved)
} catch (e: Exception) {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe expression resolved to invalid resource location: $resolved with exception: $e")
return skip()
}
} else {
actionEffect
}
return if (effectId != null) {
ActionEffects.actionEffects[effectId]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
} else {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe has no action effect identifier or expression to run")
skip()
}
}
@@ -29,6 +29,7 @@ import com.cobblemon.mod.common.util.withQueryValue
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import kotlin.random.Random
import kotlin.ranges.random
import net.minecraft.server.level.ServerPlayer
/**
@@ -17,18 +17,21 @@ import com.cobblemon.mod.common.api.npc.NPCPartyProvider
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.weightedSelection
import com.cobblemon.mod.common.util.withQueryValue
import com.cobblemon.mod.common.util.*
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import kotlin.random.Random
import net.minecraft.server.level.ServerPlayer
import kotlin.collections.List
import kotlin.collections.any
import kotlin.collections.filter
import kotlin.collections.first
import kotlin.collections.mutableListOf
import kotlin.collections.mutableMapOf
import kotlin.collections.randomOrNull
import kotlin.collections.set
import kotlin.collections.toMutableList
import kotlin.random.Random
/**
* A provider of a party for battling the NPC. It generates a party using a more complex process
@@ -12,10 +12,10 @@ import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
enum class PokedexCategoryFilterType {
@@ -14,11 +14,11 @@ import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.itemRegistry
@@ -49,7 +49,6 @@ import com.mojang.brigadier.StringReader
import com.mojang.serialization.Codec
import com.mojang.serialization.JsonOps
import java.util.UUID
import kotlin.jvm.optionals.getOrNull
import kotlin.math.min
import kotlin.random.Random
import net.minecraft.ResourceLocationException
@@ -66,6 +65,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import kotlin.jvm.optionals.getOrNull
/**
* A grouping of typical, selectable properties for a Pokémon. This is serializable
@@ -168,8 +168,8 @@ open class PokemonProperties {
parseIntProperty(keyPairs, listOf("${statName}_iv"))?.coerceIn(0, IVs.MAX_VALUE)?.let { maybeIVs[stat] = it }
parseIntProperty(keyPairs, listOf("${statName}_ev"))?.coerceIn(0, EVs.MAX_STAT_VALUE)?.let { maybeEVs[stat] = it }
}
props.evs = maybeEVs.takeIf { it.total() > 0 }
props.ivs = maybeIVs.takeIf { it.total() > 0 }
props.ivs = maybeIVs
props.evs = maybeEVs
props.updateAspects()
return props
@@ -519,18 +519,29 @@ open class PokemonProperties {
}
fun matches(properties: PokemonProperties): Boolean {
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
return this.commonMatches(properties) && this.customProperties.containsAll(properties.customProperties)
return properties.asString() == this.asString()
}
// Undefined properties will match whatever they're compared with
private fun commonMatches(pokemon: Pokemon): Boolean {
level?.takeIf { it != pokemon.level }?.let { return false }
shiny?.takeIf { it != pokemon.shiny }?.let { return false }
gender?.takeIf { it != pokemon.gender }?.let { return false }
species?.takeIf { it.asSpecies() != pokemon.species }?.let { return false }
species?.run {
try {
val species = if (this == "random") {
PokemonSpecies.species.random()
} else {
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace()) ?: return@run
}
if (pokemon.species != species) {
return false
}
} catch (e: ResourceLocationException) {
return false
}
}
nickname?.takeIf { it.string != pokemon.nickname?.string }?.let { return false }
form?.takeIf { !it.equals(pokemon.form.formOnlyShowdownId(), true) }?.let { return false }
form?.takeIf { !it.equals(pokemon.form.name, true) }?.let { return false }
friendship?.takeIf { it != pokemon.friendship }?.let { return false }
fullness?.takeIf { it != pokemon.currentFullness }?.let { return false }
pokeball?.takeIf { it != pokemon.caughtBall.name.toString() }?.let { return false }
@@ -573,36 +584,6 @@ open class PokemonProperties {
return true
}
// Undefined properties will match whatever they're compared with
private fun commonMatches(properties: PokemonProperties): Boolean {
level?.takeIf { it != properties.level }?.let { return false }
shiny?.takeIf { it != properties.shiny }?.let { return false }
gender?.takeIf { it != properties.gender }?.let { return false }
species?.takeIf { it.asSpecies() != properties.species?.asSpecies() }?.let { return false }
nickname?.takeIf { it.string != properties.nickname?.string }?.let { return false }
form?.takeIf { it != properties.form }?.let { return false }
friendship?.takeIf { it != properties.friendship }?.let { return false }
pokeball?.takeIf { it != properties.pokeball }?.let { return false }
nature?.takeIf { it != properties.nature }?.let { return false }
ability?.takeIf { it != properties.ability }?.let { return false }
status?.takeIf { it != properties.status }?.let { return false }
ivs?.forEach{ stat ->
if (stat.value != properties.ivs?.get(stat.key)) { return false }
}
evs?.forEach{ stat ->
if (stat.value != properties.evs?.get(stat.key)) { return false }
}
type?.takeIf { it != properties.type }?.let { return false }
teraType?.takeIf { it != properties.teraType }?.let { return false }
dmaxLevel?.takeIf { it != properties.dmaxLevel }?.let { return false }
gmaxFactor?.takeIf { it != properties.gmaxFactor }?.let { return false }
tradeable?.takeIf { it != properties.tradeable }?.let { return false }
originalTrainer?.takeIf { it != properties.originalTrainer }?.let{ return false }
originalTrainerType?.takeIf { it != properties.originalTrainerType }?.let{ return false }
moves?.takeIf { it.any { move -> properties.moves?.none { it == move } == true } }?.let { return false }
return true
}
// TODO Review the need for this, usage for us is in commands that deviate from the behavior established by multiple Pokémon query equivalent
fun isSubSetOf(properties: PokemonProperties): Boolean {
level?.takeIf { it != properties.level }?.let { return false }
@@ -778,6 +759,7 @@ open class PokemonProperties {
shiny?.let { json.addProperty(DataKeys.POKEMON_SHINY, it) }
gender?.let { json.addProperty(DataKeys.POKEMON_GENDER, it.name) }
species?.let { json.addProperty(DataKeys.POKEMON_SPECIES_TEXT, it) }
nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, it.string) }
form?.let { json.addProperty(DataKeys.POKEMON_FORM_ID, it) }
friendship?.let { json.addProperty(DataKeys.POKEMON_FRIENDSHIP, it) }
fullness?.let { json.addProperty(DataKeys.POKEMON_FULLNESS, it) }
@@ -814,6 +796,7 @@ open class PokemonProperties {
shiny = json.get(DataKeys.POKEMON_SHINY)?.asBoolean
gender = json.get(DataKeys.POKEMON_GENDER)?.asString?.let { Gender.valueOf(it) }
species = json.get(DataKeys.POKEMON_SPECIES_TEXT)?.asString
nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let(Component::literal)
form = json.get(DataKeys.POKEMON_FORM_ID)?.asString
friendship = json.get(DataKeys.POKEMON_FRIENDSHIP)?.asInt
fullness = json.get(DataKeys.POKEMON_FULLNESS)?.asInt
@@ -921,15 +904,4 @@ open class PokemonProperties {
}
fun hasSpecies() = species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) } != null
private fun String.asSpecies() =
try {
if (this == "random") {
PokemonSpecies.species.random()
} else {
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace())
}
}
catch (e: ResourceLocationException) {
null
}
}
@@ -12,8 +12,6 @@ import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.abilities.AbilityPool
import com.cobblemon.mod.common.api.abilities.AbilityTemplate
import com.cobblemon.mod.common.api.abilities.CommonAbility
import com.cobblemon.mod.common.api.abilities.PotentialAbility
import com.cobblemon.mod.common.api.ai.SleepDepth
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
@@ -32,14 +30,14 @@ import com.cobblemon.mod.common.api.pokemon.PokemonSpecies.getByIdentifier
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffect
import com.cobblemon.mod.common.api.pokemon.effect.adapter.ShoulderEffectAdapter
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.PreEvolution
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroupAdapter
import com.cobblemon.mod.common.api.pokemon.moves.Learnset
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.transformation.evolution.PreEvolution
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.TransformationTrigger
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
@@ -50,21 +48,12 @@ import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPack
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.pokemon.abilities.SpecialAbility
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.ai.ObtainableItemCondition
import com.cobblemon.mod.common.pokemon.ai.ObtainableItemConditionAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonPreEvolutionAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonRequirementAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.CobblemonTriggerAdapter
import com.cobblemon.mod.common.pokemon.transformation.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.pokemon.transformation.evolution.Evolution
import com.cobblemon.mod.common.pokemon.transformation.form.GigantamaxForm
import com.cobblemon.mod.common.pokemon.transformation.form.PermanentForm
import com.cobblemon.mod.common.pokemon.transformation.form.StandardForm
import com.cobblemon.mod.common.pokemon.transformation.form.TemporaryForm
import com.cobblemon.mod.common.pokemon.transformation.requirements.HeldItemRequirement
import com.cobblemon.mod.common.pokemon.transformation.requirements.MoveSetRequirement
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonPreEvolutionAdapter
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
import com.cobblemon.mod.common.util.adapters.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.common.collect.HashBasedTable
@@ -115,8 +104,10 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(ExperienceGroup::class.java, ExperienceGroupAdapter)
.registerTypeAdapter(EntityDimensions::class.java, EntityDimensionsAdapter)
.registerTypeAdapter(Learnset::class.java, LearnsetAdapter)
.registerTypeAdapter(Evolution::class.java, CobblemonEvolutionAdapter)
.registerTypeAdapter(AABB::class.java, BoxAdapter)
.registerTypeAdapter(AbilityPool::class.java, AbilityPoolAdapter)
.registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(PreEvolution::class.java, CobblemonPreEvolutionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(Set::class.java, Evolution::class.java).type, LazySetAdapter(Evolution::class))
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
@@ -137,10 +128,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter)
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
.registerTypeAdapter(TransformationTrigger::class.java, CobblemonTriggerAdapter)
.registerTypeAdapter(TransformationRequirement::class.java, CobblemonRequirementAdapter)
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
.registerTypeAdapter(FormData::class.java, FormAdapter)
.registerTypeAdapter(RidingBehaviourSettings::class.java, RidingBehaviourSettingsAdapter)
.registerTypeAdapter(RideSoundSettingsList::class.java, RideSoundSettingsListAdapter)
.registerTypeAdapter(ObtainableItemCondition::class.java, ObtainableItemConditionAdapter)
@@ -164,9 +152,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
val implemented: List<Species>
get() = this.species.filter { it.implemented }
val forms: Collection<FormData>
get() = this.species.flatMap { it.allForms }
init {
SpeciesAdditions.observable.subscribe {
this.species.forEach(Species::initialize)
@@ -261,18 +246,34 @@ object PokemonSpecies : JsonDataRegistry<Species> {
}
/**
* The representation of [FormData] in the context of Showdown.
* The representation of a [Species] and/or [FormData] in the context of showdown.
* This is intended as a sort of DTO that can be easily converted between JSON and Java/JS objects.
*
* @param form The [FormData] being converted into a species (Showdown considers them species).
* @param species The [Species] being converted or the base species if the form is not null.
* @param form The [FormData] being converted int o species (Showdown considers them species) will be null when dealing with the base form.
*/
@Suppress("unused")
internal open class ShowdownSpecies(form: FormData) {
val num = form.species.nationalPokedexNumber
val name = form.showdownName()
val types = form.types.map { it.name }
val eggGroups = form.eggGroups.map { it.showdownID }
val gender: String? = when (form.maleRatio) {
internal class ShowdownSpecies(species: Species, form: FormData?) {
val num = species.nationalPokedexNumber
val name = if (form != null) "${createShowdownName(species)}-${form.name}" else createShowdownName(species)
val baseSpecies = if (form != null) createShowdownName(species) else this.name
val forme = form?.name
// ToDo baseForme
val otherFormes = if (form == null && species.forms.isNotEmpty()) species.forms.map { "${this.name}-${it.name}" } else emptyList()
val formeOrder = if (form == null && this.otherFormes.isNotEmpty()) arrayListOf(this.name, *this.otherFormes.toTypedArray()) else emptyList()
val abilities: Map<String, String> = mapOf(
"0" to "No Ability",
"1" to "No Ability",
"H" to "No Ability",
"S" to "No Ability"
)
val types = (form?.types ?: species.types).map { it.name }
val preevo: String? = (form?.preEvolution ?: species.preEvolution)?.let { if (it.form == it.species.standardForm) createShowdownName(it.species) else "${createShowdownName(it.species)}-${it.form.name}" }
// For the context of battles the content here doesn't matter whatsoever and due to how PokemonProperties work we can't guarantee an actual specific species is defined.
val evos = if ((form?.evolutions ?: species.evolutions).isEmpty()) emptyList() else arrayListOf("")
val nfe = this.evos.isNotEmpty()
val eggGroups = (form?.eggGroups ?: species.eggGroups).map { it.showdownID }
val gender: String? = when (form?.maleRatio ?: species.maleRatio) {
0F -> "F"
1F -> "M"
-1F, 1.125F -> "N"
@@ -280,145 +281,47 @@ object PokemonSpecies : JsonDataRegistry<Species> {
}
val genderRatio = if (this.gender == null)
mapOf(
"M" to (form.maleRatio),
"F" to (1F - (form.maleRatio))
"maleRatio" to (form?.maleRatio ?: species.maleRatio),
"femaleRation" to (1F - (form?.maleRatio ?: species.maleRatio))
) else null
val baseStats = Stats.PERMANENT.associateBy({ it.showdownId }, { form.baseStats[it] ?: 1 })
val heightm = form.height / 10
val weightkg = form.weight / 10
val baseStats = mapOf(
"hp" to (form?.baseStats?.get(Stats.HP) ?: species.baseStats[Stats.HP] ?: 1),
"atk" to (form?.baseStats?.get(Stats.ATTACK) ?: species.baseStats[Stats.ATTACK] ?: 1),
"def" to (form?.baseStats?.get(Stats.DEFENCE) ?: species.baseStats[Stats.DEFENCE] ?: 1),
"spa" to (form?.baseStats?.get(Stats.SPECIAL_ATTACK) ?: species.baseStats[Stats.SPECIAL_ATTACK] ?: 1),
"spd" to (form?.baseStats?.get(Stats.SPECIAL_DEFENCE) ?: species.baseStats[Stats.SPECIAL_DEFENCE] ?: 1),
"spe" to (form?.baseStats?.get(Stats.SPEED) ?: species.baseStats[Stats.SPEED] ?: 1)
)
val heightm = (form?.height ?: species.height) / 10
val weightkg = (form?.weight ?: species.weight) / 10
// This is ugly, but we already have it hardcoded in the mod anyway
val maxHP = if (this.num == 292) 1 else null
val cannotDynamax = form.dynamaxBlocked
val abilities = form.showdownAbilityMapping()
// Common fields exempt from standard forms
val baseSpecies = if (form !is StandardForm) form.species.standardForm.showdownName() else null
val forme = if (form !is StandardForm) form.name else null
/**
* The following fields are optional and currently omitted
*
* cosmeticFormes (not needed, we have species features)
* addedType (tertiary type [by name or showdownid] added by moves or abilities)
* tier (smogon tryhard bs)
* doublesTier (smogon tryhard bs)
* natDexTier (smogon tryhard bs)
* evoType (the evolution method used to evolve from 'prevo'; trade', 'useItem', 'levelMove', 'levelExtra', 'levelFriendship', 'levelHold', 'other')
* evoMove (the move [by name or showdownid] used to evolve from 'prevo')
* evoLevel (the minimum level required to evolve from 'prevo')
* canHatch (flag for baby pokemon)
* color (color, value is arbitrary)
* tags (flags for filtering pokemon; 'Mega', 'Mythical', 'Sub-Legendary', 'Restricted Legendary', 'Paradox')
* unreleasedHidden (whether this pokemon has an unreleased hidden ability)
* maleOnlyHidden (whether it is only possible to get the hidden ability on a male pokemon)
* gmaxUnreleased (whether this pokemon has an unreleased gmax form)
* pokemonGoData (no one cares)
*/
val maxHP = if (species.showdownId() == "shedinja") 1 else null
val canGigantamax: String? = if (form?.gigantamaxMove != null) form.gigantamaxMove.name else null
val cannotDynamax = form?.dynamaxBlocked ?: species.dynamaxBlocked
// ToDo battleOnly
// ToDo changesFrom
val requiredMove = form?.requiredMove
val requiredItem = form?.requiredItem
val requiredItems = form?.requiredItems
}
/**
* The representation of a [PermanentForm] in the context of Showdown.
*
* @param form The [PermanentForm] being converted into a species.
*/
internal open class ShowdownPermanentForm(form: PermanentForm) : ShowdownSpecies(form) {
// species this form evolves from
val prevo = form.preEvolution?.form?.showdownName()
// For the context of battles the content here doesn't matter whatsoever and due to how PokemonProperties work we can't guarantee an actual specific species is defined.
val evos = form.evolutions.map { "" }
// not fully evolved
val nfe = this.evos.isNotEmpty()
// whether there is a gmax form to change to
val canGigantamax: String? = form.changeableForms.filterIsInstance<GigantamaxForm>().firstOrNull()?.name // TODO id better
}
/**
* The representation of a [StandardForm] in the context of Showdown.
*
* @param form The [StandardForm] being converted into a species.
*/
internal class ShowdownStandardForm(form: StandardForm) : ShowdownPermanentForm(form) {
// list of all forms descending from this base species
val otherFormes = form.flattenForms().map { it.showdownName() }
// list of forms [by name or showdownid] in the order they appear in game [union of baseSpecies, otherFormes, and cosmeticFormes] with the exception of ending with 'Gmax' forms
val formeOrder = if (this.otherFormes.isNotEmpty()) arrayListOf(this.name, *this.otherFormes.toTypedArray()) else null
// TODO we don't enforce any form order with our Species registration - right now this looks like only a problem with Mega Rayquaza, but investigate changes needed on Showdown's end to enable these lists to be more dynamic
}
/**
* The representation of a [TemporaryForm] in the context of Showdown.
*
* @param form The [TemporaryForm] being converted into a species.
*/
internal class ShowdownTemporaryForm(form: TemporaryForm) : ShowdownSpecies(form) {
// form change can occur during a battle
val battleOnly = if (form.battleOnly) form.parentForm.showdownName() else null
// form change can occur outside of battle (mutually exclusive with battleOnly)
val changesFrom = if (!form.battleOnly) form.parentForm.showdownName() else null
// pokemon must know this move to be in this form
val requiredMove = form.requirements.filterIsInstance<MoveSetRequirement>().firstOrNull()?.move?.showdownId() // TODO update showdown to support 'requiredMoves'
// pokemon must hold one of these item(s) to be in this form
val requiredItems = form.requirements.filterIsInstance<HeldItemRequirement>().firstOrNull()?.let { requirement ->
try {
requirement.itemCondition.items.get().map { BuiltInRegistries.ITEM.getKey(it.value()).path } // TODO held items on showdown are ignorant of namespace
}
catch (e: NoSuchElementException)
{
Cobblemon.LOGGER.error("Failed to resolve required held item for ${form.showdownId()}}") // TODO this needs to be done after tags are loaded...
null
}
private fun createShowdownName(species: Species): String {
if (species.resourceIdentifier.namespace == Cobblemon.MODID) {
return species.name
}
}
/** Accommodate for Showdown bullshit. */
/*
private fun TemporaryForm.showdownParentForm(): Any {
if (this.parentOverrides.isNotEmpty())
return this.species.standardForm.flattenForms().filter {
parentOverrides.contains(it.showdownId())
}.map {
it.showdownName()
}
else
return parentForm.showdownName()
}
*/
/**
* Constructs a mapping of the [PotentialAbility]s belonging to a [FormData] in Showdown identifiable format.
*
* @return A map of type (numeric for [CommonAbility]s, H for [HiddenAbility], S for [SpecialAbility]) to showdownid.
*/
private fun FormData.showdownAbilityMapping(): Map<String, String>? {
// potential abilities
val commonAbilities = this.abilities.filterIsInstance<CommonAbility>()
val hiddenAbility = this.abilities.find { it is HiddenAbility }
val specialAbility = this.abilities.find { it is SpecialAbility }
// can have multiple common abilities
val abilities = mutableMapOf<String, String>()
val mapping: (String, PotentialAbility) -> Unit = { key, ability ->
abilities.put(key, ability.template.showdownId())
}
// can only have one hidden and one special ability
commonAbilities.forEachIndexed { index, ability -> mapping(index.toString(), ability) }
hiddenAbility?.let { ability -> mapping("H", ability) }
specialAbility?.let { ability -> mapping("S", ability) }
return if (abilities.isEmpty()) null else abilities
return "${species.resourceIdentifier.namespace}:${species.name}"
}
internal fun allShowdownSpecies(): Map<String, String> {
val result = mutableMapOf<String, String>()
this.species.forEach { species ->
species.permanentForms.forEach { form ->
val formSpecies = ShowdownSpecies(form)
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name.lowercase(), "")] = this.gson.toJson(formSpecies)
}
species.temporaryForms.forEach { form ->
val formSpecies = ShowdownSpecies(form)
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name.lowercase(), "")] = this.gson.toJson(formSpecies)
this.species.forEach {species ->
val baseSpecies = ShowdownSpecies(species, null)
result[ShowdownIdentifiable.REGEX.replace(baseSpecies.name.lowercase(), "")] = this.gson.toJson(baseSpecies)
species.forms.forEach { form ->
if (form != species.standardForm) {
val formSpecies = ShowdownSpecies(species, form)
result[ShowdownIdentifiable.REGEX.replace(formSpecies.name.lowercase(), "")] = this.gson.toJson(formSpecies)
}
}
}
return result
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.adapters
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.google.gson.JsonDeserializer
import com.google.gson.JsonSerializer
import kotlin.reflect.KClass
/**
* Saves and loads [Requirement]s with JSON.
* For the default implementation see [com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter].
*
* @author Licious
* @since March 21st, 2022
*/
interface RequirementAdapter : JsonDeserializer<Requirement>, JsonSerializer<Requirement> {
/**
* Registers the given type of [Requirement] to it's associated ID for deserialization.
*
* @param T The type of [Requirement].
* @param id The id of the evolution event.
* @param type The [KClass] of the type.
*/
fun <T : Requirement> registerType(id: String, type: KClass<T>)
}
@@ -1,32 +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.pokemon.aspect
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeature
import com.cobblemon.mod.common.pokemon.Pokemon
/**
* A provider of aspects for a [SpeciesFeature].
*
* @author Segfault Guy
* @since Feb 12th, 2024
*/
interface FeatureAspectProvider: AspectProvider {
var default: String?
var isAspect: Boolean
/** Returns true if this [aspect] is provided by this provider. */
fun matches(aspect: String): Boolean
/** Creates a [SpeciesFeature] that provides the respective [aspect]. */
fun from(aspect: String): SpeciesFeature<*>?
/** Sets the [aspect] that's provided. */
fun set(pokemon: Pokemon, aspect: String)
}
@@ -24,11 +24,11 @@ interface SingleConditionalAspectProvider : AspectProvider {
fun getForFeature(name: String): SingleConditionalAspectProvider {
return object : SingleConditionalAspectProvider {
override val aspect: String = name
override fun meetsCondition(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.value == true
override fun meetsCondition(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.enabled == true
override fun meetsCondition(pokemonProperties: PokemonProperties) = pokemonProperties
.customProperties
.filterIsInstance<FlagSpeciesFeature>()
.any { it.name == name && it.value }
.any { it.name == name && it.enabled }
}
}
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
/**
* Represents an evolution of a [Pokemon] that can only occur during specific actions and with added context.
* For the default implementations see [ItemInteractionEvolution] & [TradeEvolution].
*
* @param RC The context given at runtime when querying the [Evolution].
* @param TC The context that is serialized from JSON during species loading, this is what the [RC] is expected to match against.
* @author Licious
* @since March 19th, 2022
*/
interface ContextEvolution<RC, TC> : Evolution {
/**
* The target context for this [Evolution] to even be tested.
*/
val requiredContext: TC
/**
* Attempts to evolve the given [Pokemon] under the given context of type [RC].
*
* @param pokemon The [Pokemon] attempting to evolve.
* @param context The context of this query.
* @return If the evolution was successful.
*/
fun attemptEvolution(pokemon: Pokemon, context: RC): Boolean {
if (this.testContext(pokemon, context) && super.test(pokemon)) {
return super.evolve(pokemon)
}
return false
}
/**
* Checks if the given context is valid for the [requiredContext].
*
* @param pokemon The [Pokemon] attempting to evolve.
* @param context The context of this query.
* @return If the context matched the [requiredContext].
*/
fun testContext(pokemon: Pokemon, context: RC): Boolean
}
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.pokemon.transformation.evolution
package com.cobblemon.mod.common.api.pokemon.evolution
import com.cobblemon.mod.common.Cobblemon.playerDataManager
import com.cobblemon.mod.common.CobblemonItems
@@ -17,23 +17,20 @@ import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.PokemonGainedEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
import com.cobblemon.mod.common.api.moves.BenchedMove
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.transformation.Transformation
import com.cobblemon.mod.common.api.pokemon.transformation.requirement.TransformationRequirement
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.ContextTrigger
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.PassiveTrigger
import com.cobblemon.mod.common.api.pokemon.transformation.trigger.TransformationTrigger
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.pokemon.transformation.triggers.LevelUpTrigger
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
@@ -44,32 +41,58 @@ import net.minecraft.world.item.ItemStack
/**
* Represents an evolution of a [Pokemon], this is the server side counterpart of [EvolutionDisplay].
* Following Pokémon these can be triggered by 3 possible events, level ups, trades or using an item.
* For the default implementations see [LevelUpEvolution], [TradeEvolution] & [ItemInteractionEvolution].
* Also see [PassiveEvolution] & [ContextEvolution].
*
* @author Licious
* @since March 19th, 2022
*/
class Evolution(
override val id: String = "",
/** The [TransformationRequirement]s that need to be satisfied for this evolution to start. */
override val requirements: Set<TransformationRequirement> = setOf(),
/** The [TransformationTrigger] to kickstart this evolution. */
override val trigger: TransformationTrigger = LevelUpTrigger(),
/** If this evolution can be deferred and started whenever rather than immediately on trigger. */
override val optional: Boolean = true,
/** If this evolution needs its requirements reevaluated to remain valid. */
override val reevaluate: Boolean = true,
/** The result of this evolution. */
val result: PokemonProperties = PokemonProperties(),
/** The shed result of this evolution. */
val shedder: PokemonProperties? = null,
/** The [MoveTemplate]s that will be offered to be learnt upon evolving. */
val learnableMoves: Set<MoveTemplate> = setOf(),
/** The items that will drop once the evolution finishes. */
val drops: DropTable = DropTable()
) : Transformation {
interface Evolution : EvolutionLike {
override fun test(pokemon: Pokemon, context: ContextTrigger.Context?): Boolean {
val result = super.test(pokemon, context)
/**
* The result of this evolution.
*/
val result: PokemonProperties
/**
* The shed result of this evolution.
*/
val shedder: PokemonProperties?
/**
* If this evolution allows the user to choose when to start it or not.
*/
var optional: Boolean
/**
* If this [Evolution] will consume the [Pokemon.heldItem]
*/
var consumeHeldItem: Boolean
/**
* The [Requirement]s behind this evolution.
*/
val requirements: MutableSet<Requirement>
/**
* The [MoveTemplate]s that will be offered to be learnt upon evolving.
*/
val learnableMoves: MutableSet<MoveTemplate>
/**
* The items that will drop once the evolution finishes.
*/
val drops: DropTable
/**
* Checks if the given [Pokemon] passes all the conditions and is ready to evolve.
*
* @param pokemon The [Pokemon] being queried.
* @return If the [Evolution] can start.
*/
fun test(pokemon: Pokemon): Boolean {
val result = this.requirements.all { requirement -> requirement.check(pokemon) }
val event = EvolutionTestedEvent(pokemon, this, result, result)
CobblemonEvents.EVOLUTION_TESTED.post(event)
return event.result
@@ -77,21 +100,20 @@ class Evolution(
/**
* Starts this evolution or queues it if [optional] is true.
* Side effects may occur based on [consumeHeldItem].
*
* @param pokemon The [Pokemon] being evolved.
* @param context The optional [TriggerContext] needed to evolve.
* @return Whether the [Evolution] was successful.
*/
override fun tryStart(pokemon: Pokemon, context: ContextTrigger.Context?): Boolean {
if (this.test(pokemon, context)) {
return if (this.optional)
pokemon.evolutionProxy.server().add(this)
else {
this.perform(pokemon)
true
}
fun evolve(pokemon: Pokemon): Boolean {
if (this.consumeHeldItem) {
pokemon.swapHeldItem(ItemStack.EMPTY)
}
return false
if (this.optional) {
// All the networking is handled under the hood, see EvolutionController.
return pokemon.evolutionProxy.server().add(this)
}
this.forceEvolve(pokemon)
return true
}
fun shed(pokemon: Pokemon): Boolean {
@@ -131,29 +153,32 @@ class Evolution(
*
* @param pokemon The [Pokemon] being evolved.
*/
override fun perform(pokemon: Pokemon) {
fun forceEvolve(pokemon: Pokemon) {
// This is a switch to enable/disable the evolution effect while we get particles improved
val useEvolutionEffect = true
if (pokemon.state is ShoulderedState) {
pokemon.recall()
pokemon.tryRecallWithAnimation()
}
val preEvoName = pokemon.getDisplayName()
val pokemonEntity = pokemon.entity
if (pokemonEntity == null) {
if (pokemonEntity == null || !useEvolutionEffect) {
pokemon.getOwnerPlayer()?.playNotifySound(CobblemonSounds.EVOLUTION_UI, SoundSource.PLAYERS, 1F, 1F)
fulfill(pokemon)
evolutionMethod(pokemon)
pokemon.getOwnerPlayer()?.sendSystemMessage(lang("ui.evolve.into", preEvoName, pokemon.species.translatedName))
} else {
pokemonEntity.entityData.set(PokemonEntity.TRANSFORMATION_STARTED, true)
pokemonEntity.entityData.set(PokemonEntity.EVOLUTION_STARTED, true)
pokemonEntity.navigation.stop()
pokemonEntity.after(1F) {
evolutionAnimation(pokemonEntity)
}
pokemonEntity.after(11.2F) {
fulfill(pokemon)
evolutionMethod(pokemon)
}
pokemonEntity.after(seconds = 12F) {
cryAnimation(pokemonEntity)
pokemonEntity.entityData.set(PokemonEntity.TRANSFORMATION_STARTED, false)
pokemonEntity.entityData.set(PokemonEntity.EVOLUTION_STARTED, false)
pokemon.getOwnerPlayer()?.sendSystemMessage(lang("ui.evolve.into", preEvoName, pokemon.species.translatedName))
}
}
@@ -169,13 +194,13 @@ class Evolution(
playPoseableAnimationPacket.sendToPlayersAround(pokemon.x, pokemon.y, pokemon.z, 128.0, pokemon.level().dimension())
}
override fun fulfill(pokemon: Pokemon) {
fun evolutionMethod(pokemon: Pokemon) {
// This ensures the Pokémon doesn't lose moves during evolution
// (e.g., Oshawott evolving at level 17 knowing Razor Shell, while Dewott only learns it at level 18).
val previousSpeciesLearnableMoves = pokemon.relearnableMoves
val sourcePokemon = pokemon.clone()
this.result.apply(pokemon)
val movesToLearn = previousSpeciesLearnableMoves + this.learnableMoves
@@ -199,7 +224,8 @@ class Evolution(
pokemon.benchedMoves.update()
// we want to instantly tick for example you might only evolve your Bulbasaur at level 34 so Venusaur should be immediately available
pokemon.triggerTransformations<PassiveTrigger>()
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
this.shed(pokemon)
@@ -214,18 +240,11 @@ class Evolution(
)
}
super.fulfill(pokemon)
CobblemonEvents.EVOLUTION_COMPLETE.post(EvolutionCompleteEvent(pokemon, sourcePokemon, this))
CobblemonEvents.POKEMON_GAINED.post(PokemonGainedEvent(pokemon.getOwnerUUID()!!, pokemon))
}
override fun convertToDisplay(pokemon: Pokemon): EvolutionDisplay {
val result = pokemon.clone(true)
this.result.apply(result)
val expectedDisplay = EvolutionDisplay(this.id, result)
val event = EvolutionDisplayEvent(result, expectedDisplay, this)
CobblemonEvents.EVOLUTION_DISPLAY.post(event)
return event.display
fun applyTo(pokemon: Pokemon) {
result.apply(pokemon)
}
}
}
@@ -0,0 +1,69 @@
/*
* 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.api.pokemon.evolution.progress.EvolutionProgress
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.evolution.controller.ClientEvolutionController
import com.cobblemon.mod.common.pokemon.evolution.controller.ServerEvolutionController
/**
* Responsible for holding all available [EvolutionLike]s in the [Pokemon].
* Also handles all the networking behind them.
* For the Cobblemon default implementations see [ClientEvolutionController] & [ServerEvolutionController].
*
* @author Licious
* @since April 28th, 2022
*/
interface EvolutionController<T : EvolutionLike, out I : PreProcessor> : MutableSet<T> {
/**
* Resolves the [Pokemon] attached to this controller.
*
* @return The [Pokemon] this controller is attached to.
*/
fun pokemon(): Pokemon
/**
* Starts the given evolution on this controller.
* All the necessary networking will be handled.
*
* @param evolution The [EvolutionLike] starting.
*/
fun start(evolution: T)
/**
* Returns an immutable collection of [EvolutionProgress]es attached to this controller.
*
* @return The currently tracked [EvolutionProgress]es.
*/
fun progress(): Collection<EvolutionProgress<*>>
/**
* Attaches a [EvolutionProgress] to this controller.
*
* @param P The type of [EvolutionProgress].
* @param progress The [EvolutionProgress] being attached for tracking.
* @return The instance being tracked.
*/
fun <P : EvolutionProgress<*>> trackProgress(progress: P): P
/**
* Attempts to find an [EvolutionProgress] in [progress] or creates and tracks using [trackProgress].
*
* @param P The type of [EvolutionProgress].
* @param predicate The lambda attempting to find specific progress. This needs to ensure the [EvolutionProgress] is of type [P] or the cast will fail.
* @param progressFactory The lambda creating a new instance of type [P] if [predicate] can't find an element.
* @return The found match in [progress] or the created and now tracked with [trackProgress].
*/
fun <P : EvolutionProgress<*>> progressFirstOrCreate(predicate: (progress: EvolutionProgress<*>) -> Boolean, progressFactory: () -> P): P
fun asIntermediate(): I
}

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