Compare commits

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

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

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

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

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

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

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

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

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

ANIMATION .JSONS:
- Play Rough

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

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

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

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

Closes #1809

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

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

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

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

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

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

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

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

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

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

Translation: Cobblemon/Mod
Translate-URL: https://lang.cobblemon.com/projects/cobblemon/mod/ja/
2026-05-24 09:11:09 +00:00
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
Guilherme Pereira 4421303d3b Merge branch 'main' into evolution-tree 2026-02-24 21:03:56 -03:00
Guilherme Pereira 5b62f608da Merge branch 'main' into evolution-tree 2026-01-27 08:19:06 -03:00
Guilherme Pereira 3840e9cdec Merge branch 'main' into evolution-tree 2025-11-05 09:38:53 -03:00
Guilherme Pereira 5a2ac22bc2 attempt 3 to hide unknown pokemon from evolution tree 2025-10-20 17:44:55 -03:00
Guilherme Pereira 7991662be6 hide name from unknown pokemon in the evolution tree 2025-10-20 15:25:23 -03:00
Guilherme Pereira 8d41c7ae41 evolution tree refactoring 2025-10-20 14:53:17 -03:00
Guilherme Pereira 7768969186 attempt 2 to hide unknow pokemon from evolution tree 2025-10-16 16:54:35 -03:00
Guilherme Pereira 0720ec3565 attempt to hide unknown pokemon from evolution tree 2025-10-15 15:00:36 -03:00
Guilherme Pereira 5d89d9beb6 add support for custom icons and tooltips to the dex evolution tree 2025-10-14 00:02:04 -03:00
Guilherme Pereira 8ee737ae53 Merge branch 'main' into evolution-tree 2025-10-13 22:41:47 -03:00
Guilherme Pereira 886b960572 more requirements 2025-10-13 21:06:03 -03:00
Guilherme Pereira 2d23e88ff3 prevent pcs from exploding 2025-10-12 09:53:52 -03:00
Guilherme Pereira aaa63ebc8a fix wonkiness 2025-10-11 14:44:12 -03:00
Guilherme Pereira b35a82d89e update licenses 2025-10-11 14:32:56 -03:00
Guilherme Pereira 8662d954e3 add expand evolution tree button 2025-10-11 14:30:13 -03:00
Guilherme Pereira 94ddfc8720 add proper handling of variations, shiny and gender to evolution tree 2025-10-10 23:06:53 -03:00
Guilherme Pereira b9fcae2131 add some new requirements to evolution screen 2025-10-10 22:17:32 -03:00
Guilherme Pereira b848f2be3e add some new requirements to evolution screen 2025-10-10 02:00:36 -03:00
Guilherme Pereira f7019c943b add proper handling of mon forms to evolution tree 2025-10-10 00:12:56 -03:00
Guilherme Pereira c933eb2d71 make evolution icon be drawn on top of lines 2025-10-09 02:02:55 -03:00
Guilherme Pereira 09e9946eac add has move type and has friendship to dex evolution tree 2025-10-08 16:16:00 -03:00
Guilherme Pereira 082fcab8b0 add item evolution info to evolution tree 2025-10-08 10:42:45 -03:00
Guilherme Pereira 7bdc8d03b1 add panning to evolution tree 2025-10-07 15:48:27 -03:00
Guilherme Pereira 485e4cfb22 add evolution icon and tooltip for level up evolutions 2025-10-07 10:07:25 -03:00
Guilherme Pereira 4cd69c1b30 center evolution tree based on evolution tree size 2025-10-06 15:52:47 -03:00
Guilherme Pereira 00148452aa implement simple tree drawing algorithm for drawing evolution trees 2025-10-06 11:31:27 -03:00
Guilherme Pereira 598e08b8e6 add pokemon evolution tree page to pokedex 2025-10-03 10:20:13 -03:00
1105 changed files with 49548 additions and 8550 deletions
+1
View File
@@ -24,6 +24,7 @@ eclipse
run
runClient
runServer
utilityscripts/implementation/*.txt
# Files from Forge MDK
forge*changelog.txt
+108 -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,8 @@
- Lowered the volume of Blitzle and Zebstrika's cry
- Fixed Raichu (male) and Alolan Raichu (both genders) not displaying the correct Partner Cap when Pewter Crunchies are in the cosmetic slot.
- Regional Foods will now prioritize being eaten instead of used for healing Pokémon, shift clicking will use it as healing
- Resolved Z-Fighting on Pokédex Models
- Restored Ninjask's ability to do barrel rolls
### Fixes
- Fixed Croagunk's walkspeed
@@ -371,15 +383,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
@@ -0,0 +1,111 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.mixin.accessor.SinglePoolElementAccessor;
import com.cobblemon.mod.common.world.structureprocessors.HeightRangeStructureProcessor;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.pools.*;
import net.minecraft.world.level.levelgen.structure.pools.alias.PoolAliasLookup;
import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Optional;
@Mixin(JigsawPlacement.class)
public class JigsawPlacementMixin {
@Inject(
method = "addPieces(Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;Lnet/minecraft/core/Holder;Ljava/util/Optional;ILnet/minecraft/core/BlockPos;ZLjava/util/Optional;ILnet/minecraft/world/level/levelgen/structure/pools/alias/PoolAliasLookup;Lnet/minecraft/world/level/levelgen/structure/pools/DimensionPadding;Lnet/minecraft/world/level/levelgen/structure/templatesystem/LiquidSettings;)Ljava/util/Optional;",
at = @At("RETURN"),
cancellable = true
)
private static void onAddPieces(
Structure.GenerationContext context,
Holder<StructureTemplatePool> startPool,
Optional<ResourceLocation> startJigsawName,
int maxDepth,
BlockPos pos,
boolean useExpansionHack,
Optional<Heightmap.Types> projectStartToHeightmap,
int maxDistanceFromCenter,
PoolAliasLookup aliasLookup,
DimensionPadding dimensionPadding,
LiquidSettings liquidSettings,
CallbackInfoReturnable<Optional<Structure.GenerationStub>> cir
) {
Optional<Structure.GenerationStub> result = cir.getReturnValue();
if (result.isEmpty()) {
return;
}
BlockPos spawnPos = result.get().position();
boolean canPlace = cobblemon$canAnyStartElementPlace(context, startPool, spawnPos);
if (canPlace) {
return;
}
cir.setReturnValue(Optional.empty());
}
@Unique
private static boolean cobblemon$canAnyStartElementPlace(
Structure.GenerationContext generationContext,
Holder<StructureTemplatePool> startPool,
BlockPos startPos
) {
for (StructurePoolElement element : startPool.value().templates) {
Optional<HeightRangeStructureProcessor> heightRangeProcessor = cobblemon$getHeightRangeProcessor(element);
if (heightRangeProcessor.isEmpty()) {
return true;
}
HeightRangeStructureProcessor processor = heightRangeProcessor.get();
boolean valid = processor.isValidPlacement(
generationContext.chunkGenerator(),
generationContext.heightAccessor(),
generationContext.randomState(),
startPos
);
if (valid) {
return true;
}
}
return false;
}
@Unique
private static Optional<HeightRangeStructureProcessor> cobblemon$getHeightRangeProcessor(StructurePoolElement element) {
if (!(element instanceof SinglePoolElement)) {
return Optional.empty();
}
StructureProcessorList processorList = ((SinglePoolElementAccessor) element).getProcessors().value();
for (StructureProcessor processor : processorList.list()) {
if (processor instanceof HeightRangeStructureProcessor heightRangeStructureProcessor) {
return Optional.of(heightRangeStructureProcessor);
}
}
return Optional.empty();
}
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.core.Holder;
import net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(SinglePoolElement.class)
public interface SinglePoolElementAccessor {
@Accessor("processors")
Holder<StructureProcessorList> getProcessors();
}
@@ -308,7 +308,9 @@ object Cobblemon {
this.config.maxPokemonLevel,
this.config.maxPokemonFriendship,
this.config.maxDynamaxLevel,
this.config.unlockAllMoveDexMovesByDefault
this.config.unlockAllMoveDexMovesByDefault,
this.config.pokemonIntrinsicSizeMin,
this.config.pokemonIntrinsicSizeMax
).sendToPlayer(player)
}
@@ -131,6 +131,7 @@ import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangeP
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
@@ -439,6 +440,7 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.gui
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import net.minecraft.client.gui.components.AbstractWidget
import net.minecraft.client.gui.components.Renderable
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.gui.narration.NarrationElementOutput
import net.minecraft.network.chat.Component
@@ -55,6 +54,8 @@ abstract class ParentWidget(
}
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
if (!active) return false
return children.any {
it.mouseClicked(pMouseX, pMouseY, pButton)
}
@@ -0,0 +1,116 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.gui
import kotlin.math.max
import kotlin.math.min
interface TreeNode<T> {
val children: List<TreeNode<T>>
}
class TreeDrawingNode<T>(
val value: T,
val children: List<TreeDrawingNode<T>>,
) {
var x = 0
var y = 0
var offset = 0
}
fun <T> createDrawingTree(treeNode: TreeNode<T>): TreeDrawingNode<T> {
val root = setup(treeNode, 0, mutableListOf<Int>(), mutableListOf<Int>())
addMods(root, 0)
return root
}
@Suppress("UNCHECKED_CAST")
private fun <T> setup(
treeNode: TreeNode<T>,
depth: Int,
nexts: MutableList<Int>,
offset: MutableList<Int>,
): TreeDrawingNode<T> {
val children = treeNode.children.map { child ->
setup(child, depth + 1, nexts, offset)
}
val treeDrawingNode = TreeDrawingNode<T>(treeNode as T, children)
treeDrawingNode.y = depth
while (nexts.size <= depth) {
nexts.add(0)
}
while (offset.size <= depth) {
offset.add(0)
}
var place =
if (children.isEmpty()) {
nexts[depth]
} else if (children.size == 1) {
// children.first().x - 1
children.first().x
} else {
// (children[0].x + children[1].x) / 2
(children.first().x + children.last().x) / 2
}
offset[depth] = max(offset[depth], nexts[depth] - place)
if (children.isEmpty()) {
treeDrawingNode.x = place
} else {
treeDrawingNode.x = place + offset[depth]
}
nexts[depth] += 2
treeDrawingNode.offset = offset[depth]
return treeDrawingNode
}
private fun <T> addMods(
treeNode: TreeDrawingNode<T>,
modSum: Int,
) {
treeNode.x += modSum
val newModSum = modSum + treeNode.offset
treeNode.children.forEach { child ->
addMods(child, newModSum)
}
}
data class TreeDrawingBounds(val minX: Int, val maxX: Int, val minY: Int, val maxY: Int) {
val width = maxX - minX
val height = maxY - minY
val xCenter = (maxX + minX) / 2.0
val yCenter = (maxY + minY) / 2.0
}
fun <T> calculateBounds(treeDrawingNode: TreeDrawingNode<T>): TreeDrawingBounds {
var minX = treeDrawingNode.x
var maxX = treeDrawingNode.x
var minY = treeDrawingNode.y
var maxY = treeDrawingNode.y
for (child in treeDrawingNode.children) {
val childBounds = calculateBounds(child)
minX = min(minX, childBounds.minX)
maxX = max(maxX, childBounds.maxX)
minY = min(minY, childBounds.minY)
maxY = max(maxY, childBounds.maxY)
}
return TreeDrawingBounds(minX, maxX, minY, maxY)
}
@@ -109,7 +109,7 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
DoubleValue(pokemon.species.nationalPokedexNumber.toDouble())
}
map["types"] = {
pokemon.form.types.map { it.toString() }.asArrayValue(::StringValue)
pokemon.form.types.map { it.showdownId }.asArrayValue(::StringValue)
}
map["gender_ratio"] = {
DoubleValue(pokemon.form.maleRatio.toDouble())
@@ -72,6 +72,40 @@ abstract class AbstractPokedexManager {
} ?: PokedexEntryProgress.UNREGISTERED
}
fun getHighestKnowledgeFor(entry: PokedexEntry, form: PokedexForm?): PokedexEntryProgress {
if (form == null) return getHighestKnowledgeFor(entry)
val speciesRecord = getSpeciesRecord(entry.speciesId) ?: return PokedexEntryProgress.UNREGISTERED
val hasAllAspects = entry.conditionAspects.all(speciesRecord::hasAspect)
if (!hasAllAspects) {
return PokedexEntryProgress.UNREGISTERED
}
return speciesRecord.getFormRecord(form.displayForm)?.knowledge ?: PokedexEntryProgress.UNREGISTERED
}
fun getHighestKnowledgeFor(entry: PokedexEntry, form: PokedexForm?, aspects: Iterable<String>): PokedexEntryProgress {
val formKnowledge = getHighestKnowledgeFor(entry, form)
if (formKnowledge == PokedexEntryProgress.UNREGISTERED) return PokedexEntryProgress.UNREGISTERED
val seenAspects = getSeenAspects(entry)
val allSeenAspects = aspects
// TODO this is ugly
.filter { it ->
if (Dexes.equivalentFormsLookup[it] != null) return@filter false
if (it.uppercase() in setOf(Gender.MALE.name, Gender.FEMALE.name, Gender.GENDERLESS.name)) return@filter false
if ("shiny".equals(it, ignoreCase = true)) return@filter false
return@filter true
}
.all { it -> seenAspects.contains(it) }
if (!allSeenAspects) return PokedexEntryProgress.UNREGISTERED
return formKnowledge
}
fun getEncounteredForms(entry: PokedexEntry) : List<PokedexForm> {
return getFormsWithKnowledge(entry, PokedexEntryProgress.SEEN)
}
@@ -10,6 +10,9 @@ package com.cobblemon.mod.common.api.pokedex
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokedex.def.PokedexDef
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.PokedexDexSyncPacket
import com.cobblemon.mod.common.util.adapters.CodecBackedAdapter
@@ -40,6 +43,17 @@ object Dexes : JsonDataRegistry<PokedexDef> {
//Maps a dex id to its PokedexDef
val dexEntryMap = linkedMapOf<ResourceLocation, PokedexDef>()
val equivalentForms = mapOf(
"galar" to listOf("region-bias-galar", "bias-galar", "galar-bias", "galarian", "galar"),
"alola" to listOf("region-bias-alola", "bias-alola", "alola-bias", "alolan", "alola"),
"hisui" to listOf("region-bias-hisui", "bias-hisui", "hisui-bias", "hisuian", "hisui"),
"paldea" to listOf("region-bias-paldea", "bias-paldea", "paldea-bias", "paldean", "paldea"),
)
val equivalentFormsLookup = equivalentForms.flatMap { (key, values) ->
values.map { it to key }
}.toMap()
override fun reload(data: Map<ResourceLocation, PokedexDef>) {
dexEntryMap.clear()
data.entries.sortedBy { it.value.sortOrder }.forEach { (id, def) -> dexEntryMap[id] = def }
@@ -49,4 +63,34 @@ object Dexes : JsonDataRegistry<PokedexDef> {
override fun sync(player: ServerPlayer) {
PokedexDexSyncPacket(dexEntryMap.values).sendToPlayer(player)
}
fun findDexEntryBySpeciesId(regionId: ResourceLocation, speciesId: ResourceLocation): PokedexEntry? {
return dexEntryMap[regionId]?.getEntries()?.firstOrNull { it -> it.speciesId == speciesId }
}
fun findDexEntryBySpeciesId(speciesId: ResourceLocation): PokedexEntry? {
return findDexEntryBySpeciesId(cobblemonResource("national"), speciesId)
}
fun findRootDexEntryBySpeciesId(speciesId: ResourceLocation, formName: String): Pair<PokedexEntry, PokedexForm> {
var rootSpecies = speciesId.let { PokemonSpecies.getByIdentifier(it) }!!
while (rootSpecies.preEvolution != null) {
rootSpecies = rootSpecies.preEvolution!!.species
}
val entry = findDexEntryBySpeciesId(rootSpecies.resourceIdentifier)
?: throw RuntimeException("Root dex entry not found")
val formEquivalents = getFormEquivalents(formName)
val form =
entry.forms.firstOrNull { formEquivalents.contains(it.displayForm.lowercase()) } ?:
entry.forms.first { it.displayForm.equals("Normal", ignoreCase = true) }
return entry to form
}
fun getFormEquivalents(formName: String): List<String> {
val key = equivalentFormsLookup[formName.lowercase()]
return equivalentForms[key] ?: listOf(formName.lowercase())
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.evolution
import com.cobblemon.mod.common.pokemon.evolution.variants.*
interface EvolutionVisitor<R> {
fun visit(evolution: Evolution): R? {
return when (evolution) {
is BlockClickEvolution -> visitBlockClickEvolution(evolution)
is DummyEvolution -> visitDummyEvolution(evolution)
is ItemInteractionEvolution -> visitItemInteractionEvolution(evolution)
is LevelUpEvolution -> visitLevelUpEvolution(evolution)
is TradeEvolution -> visitTradeEvolution(evolution)
else -> null
}
}
fun visitBlockClickEvolution(blockClickEvolution: BlockClickEvolution): R
fun visitDummyEvolution(evolution: Evolution): R // TODO: Use dummyEvolution?
fun visitItemInteractionEvolution(itemInteractionEvolution: ItemInteractionEvolution): R
fun visitLevelUpEvolution(levelUpEvolution: LevelUpEvolution): R
fun visitTradeEvolution(tradeEvolution: TradeEvolution): R
}
@@ -21,7 +21,7 @@ import net.minecraft.world.entity.LivingEntity
* @author Licious
* @since March 21st, 2022
*/
interface EntityQueryRequirement : Requirement {
abstract class EntityQueryRequirement : Requirement() {
override fun check(pokemon: Pokemon): Boolean {
val queriedEntity = pokemon.entity ?: pokemon.getOwnerPlayer() ?: return false
return this.check(pokemon, queriedEntity)
@@ -34,5 +34,5 @@ interface EntityQueryRequirement : Requirement {
* @param queriedEntity The [LivingEntity] that can be compared in context of a [Level].
* @return If the requirement was satisfied.
*/
fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
abstract fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
}
@@ -23,7 +23,7 @@ import net.minecraft.world.entity.player.Player
* @author Polymeta
* @since May 6th, 2025
*/
interface OwnerQueryRequirement : Requirement {
abstract class OwnerQueryRequirement : Requirement() {
override fun check(pokemon: Pokemon): Boolean {
val owner = pokemon.getOwnerEntity() ?: return false
return when (owner) {
@@ -44,7 +44,7 @@ interface OwnerQueryRequirement : Requirement {
* @param owner The [Player] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
abstract fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
/**
* Checks if the given [Pokemon] & [NPCEntity] satisfies the requirement.
@@ -55,5 +55,5 @@ interface OwnerQueryRequirement : Requirement {
* @param owner The [NPCEntity] that owns this [Pokemon].
* @return If the requirement was satisfied.
*/
fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
abstract fun checkNPC(pokemon: Pokemon, owner: NPCEntity): Boolean
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.pokemon.requirement
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.resources.ResourceLocation
/**
* Represents a universal requirement suitable for various checks on pokemon..
@@ -22,7 +23,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 19th, 2022
*/
fun interface Requirement {
abstract class Requirement {
/**
* Checks if the given [Pokemon] satisfies the requirement.
@@ -30,6 +31,8 @@ fun interface Requirement {
* @param pokemon The [Pokemon] being queried.
* @return If the requirement was satisfied.
*/
fun check(pokemon: Pokemon): Boolean
abstract fun check(pokemon: Pokemon): Boolean
val pokedexIcon: ResourceLocation? = null
val pokedexTooltip: String? = null
}
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.requirement
import com.cobblemon.mod.common.pokemon.requirements.*
interface RequirementVisitor<R> {
fun visit(requirement: Requirement): R? {
return when (requirement) {
is AdvancementRequirement -> visitAdvancementRequirement(requirement)
is AnyRequirement -> visitAnyRequirement(requirement)
is AreaRequirement -> visitAreaRequirement(requirement)
is AttackDefenceRatioRequirement -> visitAttackDefenceRatioRequirement(requirement)
is BattleCriticalHitsRequirement -> visitBattleCriticalHitsRequirement(requirement)
is BiomeRequirement -> visitBiomeRequirement(requirement)
is BlocksTraveledRequirement -> visitBlocksTraveledRequirement(requirement)
is DamageTakenRequirement -> visitDamageTakenRequirement(requirement)
is DefeatRequirement -> visitDefeatRequirement(requirement)
is FriendshipRequirement -> visitFriendshipRequirement(requirement)
is HeldItemRequirement -> visitHeldItemRequirement(requirement)
is LevelRequirement -> visitLevelRequirement(requirement)
is MoonPhaseRequirement -> visitMoonPhaseRequirement(requirement)
is MoveSetRequirement -> visitMoveSetRequirement(requirement)
is MoveTypeRequirement -> visitMoveTypeRequirement(requirement)
is OwnerHoldsItemRequirement -> visitOwnerHoldsItemRequirement(requirement)
is PartyMemberRequirement -> visitPartyMemberRequirement(requirement)
is PokemonPropertiesRequirement -> visitPokemonPropertiesRequirement(requirement)
is PropertyRangeRequirement -> visitPropertyRangeRequirement(requirement)
is RecoilRequirement -> visitRecoilRequirement(requirement)
is StatCompareRequirement -> visitStatCompareRequirement(requirement)
is StatEqualRequirement -> visitStatEqualRequirement(requirement)
is StructureRequirement -> visitStructureRequirement(requirement)
is TimeRangeRequirement -> visitTimeRangeRequirement(requirement)
is UseMoveRequirement -> visitUseMoveRequirement(requirement)
is WeatherRequirement -> visitWeatherRequirement(requirement)
is WorldRequirement -> visitWorldRequirement(requirement)
else -> null
}
}
fun visitAdvancementRequirement(advancementRequirement: AdvancementRequirement): R
fun visitAnyRequirement(anyRequirement: AnyRequirement): R
fun visitAreaRequirement(areaRequirement: AreaRequirement): R
fun visitAttackDefenceRatioRequirement(attackDefenceRatioRequirement: AttackDefenceRatioRequirement): R
fun visitBattleCriticalHitsRequirement(battleCriticalHitsRequirement: BattleCriticalHitsRequirement): R
fun visitBiomeRequirement(biomeRequirement: BiomeRequirement): R
fun visitBlocksTraveledRequirement(blocksTraveledRequirement: BlocksTraveledRequirement): R
fun visitDamageTakenRequirement(damageTakenRequirement: DamageTakenRequirement): R
fun visitDefeatRequirement(defeatRequirement: DefeatRequirement): R
fun visitFriendshipRequirement(friendshipRequirement: FriendshipRequirement): R
fun visitHeldItemRequirement(heldItemRequirement: HeldItemRequirement): R
fun visitLevelRequirement(levelRequirement: LevelRequirement): R
fun visitMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): R
fun visitMoveSetRequirement(moveSetRequirement: MoveSetRequirement): R
fun visitMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): R
fun visitOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): R
fun visitPartyMemberRequirement(partyMemberRequirement: PartyMemberRequirement): R
fun visitPokemonPropertiesRequirement(pokemonPropertiesRequirement: PokemonPropertiesRequirement): R
fun visitPropertyRangeRequirement(propertyRangeRequirement: PropertyRangeRequirement): R
fun visitRecoilRequirement(recoilRequirement: RecoilRequirement): R
fun visitStatCompareRequirement(statCompareRequirement: StatCompareRequirement): R
fun visitStatEqualRequirement(statEqualRequirement: StatEqualRequirement): R
fun visitStructureRequirement(structureRequirement: StructureRequirement): R
fun visitTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): R
fun visitUseMoveRequirement(useMoveRequirement: UseMoveRequirement): R
fun visitWeatherRequirement(weatherRequirement: WeatherRequirement): R
fun visitWorldRequirement(worldRequirement: WorldRequirement): R
}
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.api.spawning.TimeRange.Companion.timeRanges
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.MutableComponent
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
/**
@@ -49,4 +51,25 @@ class TimeRange : IntRanges {
constructor() : super()
constructor(vararg ranges: IntRange) : super(*ranges)
fun displayName(): MutableComponent? {
val key = timeRanges.entries.firstOrNull { entry -> this == entry.value }?.key ?: return null
return lang("ui.time_range.$key")
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TimeRange) return false
if (other.ranges.size != this.ranges.size) return false
other.ranges.forEachIndexed { index, otherRange ->
if (this.ranges[index] != otherRange) return false
}
return true
}
override fun hashCode(): Int {
return ranges.hashCode()
}
}
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.MutableComponent
import net.minecraft.world.level.Level
/**
@@ -42,4 +44,7 @@ enum class MoonPhase {
fun ofWorld(world: Level): MoonPhase = VALUES[world.moonPhase]
}
fun displayName(): MutableComponent {
return lang("ui.moon_phase.${this.name.lowercase()}")
}
}
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.moves.adapters.MoveTemplateAdapter
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.TMObtainMethodAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
@@ -70,5 +71,7 @@ object TechnicalMachines : JsonDataRegistry<TechnicalMachine> {
fun getByResourceLocation(resourceLocation: ResourceLocation) = tmMap[resourceLocation]
fun getAllResourceLocations() = tmMap.keys.toSet()
override fun sync(player: ServerPlayer) {}
override fun sync(player: ServerPlayer) {
TechnicalMachineRegistrySyncPacket(tmMap.values.toList()).sendToPlayer(player)
}
}
@@ -652,9 +652,9 @@ class FossilMultiblockStructure (
const val TICKS_PER_MINUTE = 1200
const val MATERIAL_TO_START = 128
const val TIME_TO_TAKE = TICKS_PER_MINUTE * 12
const val TIME_PER_STAGE = TIME_TO_TAKE / 8
const val PROTECTION_TIME = TICKS_PER_MINUTE * 5
const val TIME_TO_TAKE = 100
const val TIME_PER_STAGE = 100 / 8
const val PROTECTION_TIME = 100
fun fromNbt(nbt: CompoundTag, registryLookup: HolderLookup.Provider, animAge: Int = -1, partialTicks: Float = 0f): FossilMultiblockStructure {
val monitorPos = NbtUtils.readBlockPos(nbt, DataKeys.MONITOR_POS).get()
@@ -34,28 +34,27 @@ import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.BASE_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.BASE_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HEADER_BAR_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.ICONS_ARROW_PADDING_AROUND
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.ICONS_PADDING_AROUND
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_ABILITIES
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_DESCRIPTION
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_DROPS
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_EVOLUTION_TREE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_ICON_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_MOVES
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.TAB_STATS
import com.cobblemon.mod.common.client.gui.pokedex.widgets.AbilitiesWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.DescriptionWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.DropsScrollingWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.EntriesScrollingWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.MovesLearnsetWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.PokemonInfoWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.SearchWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.SizeWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.StatsWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.*
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeWidget
import com.cobblemon.mod.common.client.pokedex.PokedexType
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.isInventoryKeyPressed
@@ -92,6 +91,10 @@ class PokedexGUI private constructor(
private val categoryBarOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_bar_category.png")
// TODO: separate into smaller components / widgets?
private val backgroundOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_info_overlay.png")
private val expandedBackgroundOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_info_overlay_expanded.png")
private val tabSelectArrow = cobblemonResource("textures/gui/pokedex/select_arrow.png")
private val tabIcons = arrayOf(
cobblemonResource("textures/gui/pokedex/tab_info.png"),
@@ -99,7 +102,8 @@ class PokedexGUI private constructor(
cobblemonResource("textures/gui/pokedex/tab_size.png"),
cobblemonResource("textures/gui/pokedex/tab_stats.png"),
cobblemonResource("textures/gui/pokedex/tab_drops.png"),
cobblemonResource("textures/gui/pokedex/tab_moves.png")
cobblemonResource("textures/gui/pokedex/tab_moves.png"),
cobblemonResource("textures/gui/pokedex/tab_evolution_tree.png"),
)
val arrowUpIcon = cobblemonResource("textures/gui/pokedex/arrow_up.png")
@@ -112,6 +116,8 @@ class PokedexGUI private constructor(
TAB_MOVES
)
private val ICONS_PADDING_BETWEEN = (BASE_WIDTH / 2 - ICONS_PADDING_AROUND * 2) / tabIcons.size
/**
* Attempts to open this screen for a client.
*/
@@ -130,6 +136,7 @@ class PokedexGUI private constructor(
var oldDragPosX = 0.0
var canDragRender = false
private var activeDragableElement: GuiEventListener? = null
private var filteredPokedex: Collection<PokedexDef> = mutableListOf()
private var seenCount = "0000"
@@ -153,13 +160,29 @@ class PokedexGUI private constructor(
private lateinit var scrollScreen: EntriesScrollingWidget
private lateinit var pokemonInfoWidget: PokemonInfoWidget
private lateinit var searchWidget: SearchWidget
private lateinit var pokemonNameWidget: PokemonNameWidget
private var selectedSearchByType: SearchByType = SearchByType.SPECIES
private var selectedCategoryFilter: PokedexCategoryFilterType = PokedexCategoryFilterType.ALL
private val tabButtons: MutableList<ScaledButton> = mutableListOf()
var seenShinyStates = setOf<String>()
var shiny = false
var maleRatio = -1F
var gender = Gender.GENDERLESS
var aspects = mutableSetOf<String>()
lateinit var tabInfoElement: GuiEventListener
var tabInfoIndex = TAB_DESCRIPTION
var evolutionTreeExpanded = false
set(value) {
field = value
if (::pokemonInfoWidget.isInitialized) {
pokemonInfoWidget.active = !value
pokemonInfoWidget.visible = !value
}
}
override fun renderBlurredBackground(delta: Float) {}
override fun renderMenuBackground(context: GuiGraphics) {}
@@ -178,7 +201,7 @@ class PokedexGUI private constructor(
//Info Widget
if (::pokemonInfoWidget.isInitialized) removeWidget(pokemonInfoWidget)
pokemonInfoWidget = PokemonInfoWidget(x + 180, y + 28) { newForm -> updateSelectedForm(newForm) }
pokemonInfoWidget = PokemonInfoWidget(this, x + 180, y + 28) { newForm -> updateSelectedForm(newForm) }
addRenderableWidget(pokemonInfoWidget)
setUpTabs()
@@ -190,6 +213,10 @@ class PokedexGUI private constructor(
searchWidget = SearchWidget(x + 26, y + 28, 120, HEADER_BAR_HEIGHT, update = ::updateFilters)
addRenderableWidget(searchWidget)
if (::pokemonNameWidget.isInitialized) removeWidget(pokemonNameWidget)
pokemonNameWidget = PokemonNameWidget(this, x + 180, y + 28)
addRenderableWidget(pokemonNameWidget)
if (::regionSelectWidgetUp.isInitialized) removeWidget(regionSelectWidgetUp)
regionSelectWidgetUp = ScaledButton(
buttonX = (x + 95).toFloat(),
@@ -365,6 +392,14 @@ class PokedexGUI private constructor(
shadow = true
)
blitk(
matrixStack = matrices,
texture = if (evolutionTreeExpanded) expandedBackgroundOverlay else backgroundOverlay,
x = pokemonInfoWidget.x, y = pokemonInfoWidget.y,
width = HALF_OVERLAY_WIDTH,
height = HALF_OVERLAY_HEIGHT
)
// Category filter
blitk(
matrixStack = matrices,
@@ -400,7 +435,7 @@ class PokedexGUI private constructor(
blitk(
matrixStack = matrices,
texture = tabSelectArrow,
x = (x + 191.5F + (22F * tabInfoIndex)) / SCALE,
x = (x + BASE_WIDTH / 2 + ICONS_ARROW_PADDING_AROUND + tabInfoIndex * ICONS_PADDING_BETWEEN) / SCALE,
y = (y + 177) / SCALE,
width = 12,
height = 6,
@@ -434,6 +469,7 @@ class PokedexGUI private constructor(
val canDisplayEntry = true //selectedForm?.unlockForms
if (::pokemonInfoWidget.isInitialized
&& pokemonInfoWidget.active
&& !pokemonInfoWidget.suppressViewport
&& pokemonInfoWidget.isWithinPortraitSpace(mouseX, mouseY)
&& canDisplayEntry == true
@@ -442,6 +478,12 @@ class PokedexGUI private constructor(
isDragging = true
oldDragPosX = mouseX
playSound(CobblemonSounds.POKEDEX_CLICK_SHORT)
activeDragableElement = pokemonInfoWidget
} else if (tabInfoIndex == TAB_EVOLUTION_TREE &&
::tabInfoElement.isInitialized &&
(tabInfoElement as EvolutionTreeWidget).isHovered(mouseX, mouseY)
) {
activeDragableElement = tabInfoElement
}
return try {
super.mouseClicked(mouseX, mouseY, button)
@@ -453,14 +495,18 @@ class PokedexGUI private constructor(
override fun mouseReleased(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
if (canDragRender) canDragRender = false
if (isDragging) isDragging = false
activeDragableElement = null
return super.mouseReleased(pMouseX, pMouseY, pButton)
}
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (isDragging && canDragRender) {
if (isDragging && canDragRender && activeDragableElement == pokemonInfoWidget) {
val dragOffsetY = (oldDragPosX - mouseX).toFloat()
pokemonInfoWidget.rotationY = (((pokemonInfoWidget.rotationY + dragOffsetY) % 360 + 360) % 360)
} else if (activeDragableElement == tabInfoElement) {
tabInfoElement.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
oldDragPosX = mouseX
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
@@ -551,6 +597,8 @@ class PokedexGUI private constructor(
selectedForm = CobblemonClient.clientPokedexData.getEncounteredForms(newSelectedEntry).firstOrNull()
pokemonInfoWidget.setDexEntry(selectedEntry!!)
pokemonNameWidget.update(selectedEntry!!)
displaytabInfoElement(tabInfoIndex)
}
@@ -562,7 +610,7 @@ class PokedexGUI private constructor(
for (i in tabIcons.indices) {
tabButtons.add(ScaledButton(
x + 190.5F + (i * 22F),
x + BASE_WIDTH / 2 + ICONS_PADDING_AROUND + i * ICONS_PADDING_BETWEEN,
y + 181.5F,
TAB_ICON_SIZE,
TAB_ICON_SIZE,
@@ -575,6 +623,8 @@ class PokedexGUI private constructor(
}
fun displaytabInfoElement(tabIndex: Int, update: Boolean = true) {
if (tabIndex != TAB_EVOLUTION_TREE) evolutionTreeExpanded = false
val showActiveTab = selectedEntry?.let { selectedForm in getSufficientlyKnownForms(it, tabIndex) } == true
var statSubIndex = 0
@@ -626,6 +676,9 @@ class PokedexGUI private constructor(
TAB_MOVES -> {
tabInfoElement = MovesLearnsetWidget(x + 180, y + 28)
}
TAB_EVOLUTION_TREE -> {
tabInfoElement = EvolutionTreeWidget(this, x, y)
}
}
val element = tabInfoElement
if (element is Renderable && element is NarratableEntry) {
@@ -700,6 +753,9 @@ class PokedexGUI private constructor(
selectedForm = fallbackForm
) { next -> cycleSelectedForm(next) }
}
TAB_EVOLUTION_TREE -> {
(tabInfoElement as EvolutionTreeWidget).setup(selectedEntry, selectedForm)
}
}
} else {
if (tabInfoIndex != TAB_DESCRIPTION) displaytabInfoElement(TAB_DESCRIPTION)
@@ -16,6 +16,8 @@ object PokedexGUIConstants {
const val HEADER_BAR_HEIGHT = 11
const val POKEMON_DESCRIPTION_HEIGHT = 42
const val POKEMON_DESCRIPTION_PADDING = 9
const val ICONS_PADDING_AROUND = 18.5f
const val ICONS_ARROW_PADDING_AROUND = ICONS_PADDING_AROUND + 1
const val TAB_ICON_SIZE = 16
@@ -36,6 +38,7 @@ object PokedexGUIConstants {
const val TAB_STATS = 3
const val TAB_DROPS = 4
const val TAB_MOVES = 5
const val TAB_EVOLUTION_TREE = 6
// RowScrollingWidget
const val SCROLL_BASE_HEIGHT = 141
@@ -20,31 +20,95 @@ import net.minecraft.network.chat.MutableComponent
private val tooltipEdge = cobblemonResource("textures/gui/pokedex/tooltip_edge.png")
private val tooltipBackground = cobblemonResource("textures/gui/pokedex/tooltip_background.png")
fun renderTooltip(context: GuiGraphics, text: MutableComponent, posX: Int, posY: Int, delta: Float, offsetY: Int = 0) {
fun renderTooltip(
context: GuiGraphics,
text: MutableComponent,
posX: Int,
posY: Int,
delta: Float,
offsetY: Int = 0,
) {
renderTooltip(
context,
listOf(text),
posX,
posY,
delta,
offsetY,
)
}
fun renderTooltip(
context: GuiGraphics,
text: List<MutableComponent>,
posX: Int,
posY: Int,
delta: Float,
offsetY: Int = 0,
) {
val poseStack = context.pose()
val textWidth = Minecraft.getInstance().font.width(text.font(CobblemonResources.DEFAULT_LARGE))
val tooltipWidth = textWidth + 6
val textWidth = text.maxOf { Minecraft.getInstance().font.width(it.font(CobblemonResources.DEFAULT_LARGE)) }
val tooltipPadding = 6
val tooltipWidth = textWidth + tooltipPadding
val tooltipHeight = 11
val tooltipTop = posY + offsetY
poseStack.pushPose()
poseStack.translate(0.0, 0.0, 1000.0)
Minecraft.getInstance().let {
it.mainRenderTarget.bindWrite(false)
context.enableScissor(
posX - (tooltipWidth / 2),
tooltipTop + 1,
(posX - (tooltipWidth / 2)) + tooltipWidth,
tooltipTop + 10
tooltipTop + tooltipHeight * text.size - 1
)
it.gameRenderer.processBlurEffect(delta)
context.disableScissor()
it.mainRenderTarget.bindWrite(true)
}
blitk(matrixStack = poseStack, texture = tooltipEdge, x = posX - (tooltipWidth / 2) - 1, y = tooltipTop, width = 1, height = tooltipHeight)
blitk(matrixStack = poseStack, texture = tooltipBackground, x = posX - (tooltipWidth / 2), y = tooltipTop, width = tooltipWidth, height = tooltipHeight)
blitk(matrixStack = poseStack, texture = tooltipEdge, x = posX + (tooltipWidth / 2), y = tooltipTop, width = 1, height = tooltipHeight)
drawScaledText(context = context, font = CobblemonResources.DEFAULT_LARGE, text = text, x = posX, y = tooltipTop + 1, shadow = true, centered = true)
blitk(
matrixStack = poseStack,
texture = tooltipEdge,
x = posX - (tooltipWidth / 2) - 1,
y = tooltipTop,
width = 1,
height = tooltipHeight * text.size
)
blitk(
matrixStack = poseStack,
texture = tooltipBackground,
x = posX - (tooltipWidth / 2),
y = tooltipTop,
width = tooltipWidth,
height = tooltipHeight * text.size
)
blitk(
matrixStack = poseStack,
texture = tooltipEdge,
x = posX + (tooltipWidth / 2),
y = tooltipTop,
width = 1,
height = tooltipHeight * text.size
)
val centered = text.size == 1
text.forEachIndexed { index, it ->
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = it,
x = if (centered) posX else posX - tooltipWidth / 2 + tooltipPadding / 2,
y = tooltipTop + 1 + (tooltipHeight - 2) * index,
shadow = true,
centered = centered
)
}
poseStack.popPose()
}
@@ -20,8 +20,8 @@ import net.minecraft.client.sounds.SoundManager
import net.minecraft.resources.ResourceLocation
class ScaledButton(
var buttonX: Float,
var buttonY: Float,
buttonX: Float,
buttonY: Float,
val buttonWidth: Number,
val buttonHeight: Number,
var resource: ResourceLocation? = null,
@@ -30,6 +30,18 @@ class ScaledButton(
val clickAction: Button.OnPress
): Button(buttonX.toInt(), buttonY.toInt(), buttonWidth.toInt(), buttonHeight.toInt(), "".text(), clickAction, DEFAULT_NARRATION), CobblemonRenderable {
var buttonX: Float = buttonX
set(value) {
field = value
this.x = value.toInt()
}
var buttonY: Float = buttonY
set(value) {
field = value
this.y = value.toInt()
}
var isWidgetActive = false
var isVisible = true
@@ -12,14 +12,13 @@ import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
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.text.text
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.ScrollingWidget
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_BAR_WIDTH
@@ -27,19 +26,14 @@ import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_BA
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SPACING
import com.cobblemon.mod.common.client.gui.pokedex.widgets.EntriesScrollingWidget.PokemonScrollSlotRow
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.util.Mth
import org.joml.Quaternionf
import org.joml.Vector3f
class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (PokedexEntry) -> (Unit)): ScrollingWidget<PokemonScrollSlotRow>(
width = PokedexGUIConstants.HALF_OVERLAY_WIDTH,
@@ -135,13 +129,6 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
val discoveryLevelList: MutableList<PokedexEntryProgress>,
val setPokedexEntry : (PokedexEntry) -> (Unit)
): Slot<PokemonScrollSlotRow>() {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val slotHighlight = cobblemonResource("textures/gui/pokedex/slot_select.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon_small.png")
private val unknownIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unknown.png")
private val unimplementedIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unimplemented.png")
}
val runtime = MoLangRuntime().setupClient().setup().also {
it.environment.query.addFunction("get_pokedex") { CobblemonClient.clientPokedexData.struct }
}
@@ -161,128 +148,42 @@ class EntriesScrollingWidget(val pX: Int, val pY: Int, val setPokedexEntry: (Pok
hovered: Boolean,
tickDelta: Float
) {
dexDataList.forEachIndexed { index, dexData ->
val state = FloatingState()
val species = PokemonSpecies.getByIdentifier(dexData.speciesId)
//FIXME: This may not work properly when accounting for custom pokemon with the same dex number
val pokemonNumber = (species?.nationalPokedexNumber?.toString() ?: "0").padStart(4, '0')
val speciesNumber = pokemonNumber.text()
dexDataList.forEachIndexed { index, pokedexEntry ->
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId)
val discoveryLevel = discoveryLevelList[index]
val firstVisibleForm = CobblemonClient.clientPokedexData.getEncounteredForms(dexData).firstOrNull()
val shouldDrawMon = firstVisibleForm != null
val firstVisibleForm = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry).firstOrNull()
if (species == null) {
return@forEachIndexed
}
val matrices = context.pose()
val renderablePokemon =
if (firstVisibleForm != null) {
val firstVisibleGender = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, firstVisibleForm).firstOrNull()
val shinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, firstVisibleForm)
val firstVisibleShiny = shinyStates.count() == 1 && shinyStates.first() == "shiny"
val formAspects = species.forms.firstOrNull { it.name.equals(firstVisibleForm.displayForm, ignoreCase = true) }?.aspects ?: species.standardForm.aspects
val seenAspects = CobblemonClient.clientPokedexData.getSeenAspects(pokedexEntry)
val variationAspects = pokedexEntry.variations.mapNotNull { it.aspects.firstOrNull { it in seenAspects } }
val aspectsToDraw = (pokedexEntry.displayAspects + variationAspects + formAspects + (firstVisibleGender ?: Gender.GENDERLESS).name.lowercase()).toMutableSet()
if (firstVisibleShiny) {
aspectsToDraw.add("shiny")
}
val startPosX = x + ((SCROLL_SLOT_SPACING + SCROLL_SLOT_SIZE) * index)
val startPosY = y + SCROLL_SLOT_SPACING + 1
blitk(
matrixStack = matrices,
texture = slotResource,
x = startPosX,
y = startPosY,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE
)
if (getHoveredSlotIndex(mouseX, mouseY) == index) {
blitk(
matrixStack = matrices,
texture = slotHighlight,
x = startPosX,
y = startPosY,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
vOffset = SCROLL_SLOT_SIZE,
textureHeight = SCROLL_SLOT_SIZE * 2
)
}
if (shouldDrawMon) {
val firstVisibleGender = CobblemonClient.clientPokedexData.getSeenGenders(dexData, firstVisibleForm).firstOrNull()
val shinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(dexData, firstVisibleForm)
val firstVisibleShiny = shinyStates.count() == 1 && shinyStates.first() == "shiny"
val formAspects = species.forms.firstOrNull { it.name.equals(firstVisibleForm.displayForm, ignoreCase = true) }?.aspects ?: species.standardForm.aspects
val seenAspects = CobblemonClient.clientPokedexData.getSeenAspects(dexData)
val variationAspects = dexData.variations.mapNotNull { it.aspects.firstOrNull { it in seenAspects } }
context.enableScissor(
startPosX + 1,
startPosY + 1,
startPosX + SCROLL_SLOT_SIZE - 1,
startPosY + SCROLL_SLOT_SIZE - 2
)
val aspectsToDraw = (dexData.displayAspects + variationAspects + formAspects + (firstVisibleGender ?: Gender.GENDERLESS).name.lowercase()).toMutableSet()
if (firstVisibleShiny) {
aspectsToDraw.add("shiny")
RenderablePokemon(species, aspectsToDraw)
} else {
null
}
state.currentAspects = aspectsToDraw
matrices.pushPose()
matrices.translate(startPosX + (SCROLL_SLOT_SIZE / 2.0), startPosY + 1.0, 0.0)
matrices.scale(2.5F, 2.5F, 1F)
drawProfilePokemon(
renderablePokemon = RenderablePokemon(species, aspectsToDraw),
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = state,
partialTicks = 0F,
scale = 4.5F
)
matrices.popPose()
context.disableScissor()
} else {
blitk(
matrixStack = matrices,
texture = unknownIcon,
x = startPosX + 8.5,
y = startPosY + 9,
width = 8,
height = 10
)
if (!species.implemented) {
blitk(
matrixStack = matrices,
texture = unimplementedIcon,
x = (startPosX + 14) / SCALE,
y = (startPosY + 15.5) / SCALE,
width = 7,
height = 7,
scale = SCALE
)
}
}
// Ensure elements are not hidden behind Pokémon render
matrices.pushPose()
matrices.translate(0.0, 0.0, 100.0)
drawScaledText(
context = context,
text = speciesNumber,
x = startPosX + 1.5,//2,
y = startPosY + 2.5,//2
shadow = true,
scale = SCALE
PokemonSlotWidget.render(
context,
x = x + (SCROLL_SLOT_SPACING + SCROLL_SLOT_SIZE) * index,
y = y + SCROLL_SLOT_SPACING + 1,
getHoveredSlotIndex(mouseX, mouseY) == index,
species,
renderablePokemon,
discoveryLevel,
)
if (discoveryLevel == PokedexEntryProgress.OWNED) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (startPosX + 18) / SCALE,
y = (startPosY + 1.5) / SCALE,
width = 11,
height = 11,
scale = SCALE
)
}
matrices.popPose()
}
}
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.client.gui.pokedex.widgets
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexCosmeticVariation
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.text.bold
@@ -24,8 +24,9 @@ import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.PORTRAIT_POKE_BALL_HEIGHT
@@ -51,15 +52,13 @@ import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.sounds.SoundEvent
import org.joml.Quaternionf
import org.joml.Vector3f
import java.io.FileNotFoundException
class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm) -> (Unit)) : SoundlessWidget(
class PokemonInfoWidget(val parent: PokedexGUI, val pX: Int, val pY: Int, val updateForm: (PokedexForm) -> (Unit)) : SoundlessWidget(
pX,
pY,
POKEMON_PORTRAIT_WIDTH,
@@ -81,7 +80,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
private val arrowFormLeft = cobblemonResource("textures/gui/pokedex/forms_arrow_left.png")
private val arrowFormRight = cobblemonResource("textures/gui/pokedex/forms_arrow_right.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon.png")
private val typeBar = cobblemonResource("textures/gui/pokedex/type_bar.png")
private val typeBarDouble = cobblemonResource("textures/gui/pokedex/type_bar_double.png")
@@ -99,9 +97,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
var currentEntry : PokedexEntry? = null
var speciesName: MutableComponent = Component.translatable("")
var speciesNumber: MutableComponent = "0000".text()
val runtime = MoLangRuntime().setupClient().setup().also {
it.environment.query.addFunction("get_pokedex") { CobblemonClient.clientPokedexData.struct }
}
@@ -110,10 +105,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
var selectedFormIndex: Int = 0
var type: Array<ElementalType?> = arrayOf(null, null)
var seenShinyStates: Set<String> = setOf()
var shiny = false
var maleRatio = -1F
var gender: Gender = Gender.GENDERLESS
var renderablePokemon : RenderablePokemon? = null
@@ -194,7 +185,10 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
20,
resource = buttonGenderMale,
clickAction = {
if (maleRatio > 0 && maleRatio < 1) gender = if (gender == Gender.MALE) Gender.FEMALE else Gender.MALE
val maleRatio = parent.maleRatio
if (maleRatio > 0 && maleRatio < 1) {
parent.gender = if (parent.gender == Gender.MALE) Gender.FEMALE else Gender.MALE
}
updateAspects()
}
).apply { addWidget(this) }
@@ -206,8 +200,8 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
20,
buttonNone,
clickAction = {
if (seenShinyStates.size > 1) {
shiny = !shiny
if (parent.seenShinyStates.size > 1) {
parent.shiny = !parent.shiny
updateAspects()
}
}
@@ -262,8 +256,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
val currentEntry = this.currentEntry ?: return
val hasKnowledge =
CobblemonClient.clientPokedexData.getKnowledgeForSpecies(currentEntry.speciesId) != PokedexEntryProgress.UNREGISTERED
val hasKnowledge = CobblemonClient.clientPokedexData.getKnowledgeForSpecies(currentEntry.speciesId) != PokedexEntryProgress.UNREGISTERED
val species = currentEntry.speciesId.let { PokemonSpecies.getByIdentifier(it) } ?: return
val matrices = context.pose()
@@ -276,37 +269,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
height = HALF_OVERLAY_HEIGHT
)
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesNumber.bold(),
x = pX + 3,
y = pY + 1,
shadow = true
)
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = (if (hasKnowledge) speciesName else lang("ui.generic.question_marks")).bold(),
x = pX + 26,
y = pY + 1,
colour = 0x606B6E
)
// Caught icon
if (isSelectedPokemonOwned()) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (pX + 129) / SCALE,
y = (pY + 2) / SCALE,
width = 14,
height = 14,
scale = SCALE
)
}
if (!suppressViewport) {
blitk(
matrixStack = matrices,
@@ -569,8 +531,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
if (species != null) {
this.visibleForms = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry).toMutableList()
this.speciesNumber = species.nationalPokedexNumber.toString().padStart(4, '0').text()
this.speciesName = species.translatedName
if (forms.isNotEmpty()) {
formLeftButton.active = true
@@ -596,23 +556,23 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
variationButtons.forEach { removeWidget(it.getWidget()) }
variationButtons.clear()
seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, pokedexForm)
shiny = seenShinyStates.count() == 1 && seenShinyStates.first() == "shiny"
shinyButton.resource = if (shiny) buttonShiny else buttonNone
shinyButton.visible = shiny || seenShinyStates.size > 1
shinyButton.active = seenShinyStates.size > 1
parent.seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, pokedexForm)
parent.shiny = parent.seenShinyStates.count() == 1 && parent.seenShinyStates.first() == "shiny"
shinyButton.resource = if (parent.shiny) buttonShiny else buttonNone
shinyButton.visible = parent.shiny || parent.seenShinyStates.size > 1
shinyButton.active = parent.seenShinyStates.size > 1
val form = species.forms.find { it.name.equals(pokedexForm.displayForm, ignoreCase = true) } ?: species.standardForm
maleRatio = form.maleRatio
parent.maleRatio = form.maleRatio
val seenGenders = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, pokedexForm)
val visibleGenders = seenGenders.filter { it != Gender.GENDERLESS }
if (visibleGenders.isEmpty()) {
gender = Gender.GENDERLESS
parent.gender = Gender.GENDERLESS
genderButton.visible = false
genderButton.active = false
} else {
gender = visibleGenders.first()
parent.gender = visibleGenders.first()
genderButton.visible = true
genderButton.active = visibleGenders.size > 1
}
@@ -691,8 +651,8 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
return
}
genderButton.resource = if (gender == Gender.FEMALE) buttonGenderFemale else buttonGenderMale
shinyButton.resource = if (shiny) buttonShiny else buttonNone
genderButton.resource = if (parent.gender == Gender.FEMALE) buttonGenderFemale else buttonGenderMale
shinyButton.resource = if (parent.shiny) buttonShiny else buttonNone
val species = currentEntry?.speciesId?.let { PokemonSpecies.getByIdentifier(it) }
if (species != null) {
@@ -701,12 +661,14 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
updateType(species, form)
val aspects = mutableSetOf<String>()
if (shiny) aspects.add(SHINY_ASPECT.aspect)
val aspects = parent.aspects
aspects.clear()
if (gender == Gender.FEMALE) {
if (parent.shiny) aspects.add(SHINY_ASPECT.aspect)
if (parent.gender == Gender.FEMALE) {
aspects.add("female")
} else if (gender == Gender.MALE) {
} else if (parent.gender == Gender.MALE) {
aspects.add("male")
}
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.pokedex.widgets
import com.cobblemon.mod.common.api.gui.blitk
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.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_PORTRAIT_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
class PokemonNameWidget(
val parent: PokedexGUI,
val pX: Int,
val pY: Int,
) : SoundlessWidget(
pX,
pY,
POKEMON_PORTRAIT_WIDTH,
POKEMON_PORTRAIT_HEIGHT,
lang("ui.pokedex.pokemon_name"),
) {
companion object {
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon.png")
}
var hasKnowledge: Boolean = false
var isOwned: Boolean = false
var speciesName: MutableComponent = Component.translatable("")
var speciesNumber: MutableComponent = "0000".text()
override fun renderWidget(
context: GuiGraphics,
mouseX: Int,
mouseY: Int,
partialTick: Float
) {
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesNumber.bold(),
x = pX + 3,
y = pY + 1,
shadow = true
)
if (hasKnowledge) {
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = speciesName.bold(),
x = pX + 26,
y = pY + 1,
colour = 0x606B6E
)
}
if (isOwned) {
blitk(
matrixStack = context.pose(),
texture = caughtIcon,
x = (pX + 129) / SCALE,
y = (pY + 2) / SCALE,
width = 14,
height = 14,
scale = SCALE
)
}
}
fun update(pokedexEntry: PokedexEntry) {
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId) ?: return
val progress = CobblemonClient.clientPokedexData.getKnowledgeForSpecies(pokedexEntry.speciesId)
this.hasKnowledge = progress != PokedexEntryProgress.UNREGISTERED
this.isOwned = progress == PokedexEntryProgress.OWNED
this.speciesNumber = species.nationalPokedexNumber.toString().padStart(4, '0').text()
this.speciesName = species.translatedName
}
}
@@ -0,0 +1,151 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.pokedex.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.gui.GuiGraphics
import org.joml.Quaternionf
import org.joml.Vector3f
abstract class PokemonSlotWidget {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val slotHighlight = cobblemonResource("textures/gui/pokedex/slot_select.png")
private val caughtIcon = cobblemonResource("textures/gui/pokedex/caught_icon_small.png")
private val unknownIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unknown.png")
private val unimplementedIcon = cobblemonResource("textures/gui/pokedex/pokedex_slot_unimplemented.png")
fun render(
context: GuiGraphics,
x: Int,
y: Int,
isHovered: Boolean,
species: Species,
renderablePokemon: RenderablePokemon?,
discoveryLevel: PokedexEntryProgress,
) {
val shouldDrawMon = renderablePokemon != null
// FIXME: This may not work properly when accounting for custom pokemon with the same dex number
val pokemonNumber = species.nationalPokedexNumber.toString().padStart(4, '0')
val speciesNumber = pokemonNumber.text()
val matrices = context.pose()
blitk(
matrixStack = matrices,
texture = slotResource,
x = x,
y = y,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
)
if (isHovered) {
blitk(
matrixStack = matrices,
texture = slotHighlight,
x = x,
y = y,
width = SCROLL_SLOT_SIZE,
height = SCROLL_SLOT_SIZE,
vOffset = SCROLL_SLOT_SIZE,
textureHeight = SCROLL_SLOT_SIZE * 2,
)
}
if (shouldDrawMon && discoveryLevel != PokedexEntryProgress.UNREGISTERED) {
context.enableScissor(
x + 1,
y + 1,
x + SCROLL_SLOT_SIZE - 1,
y + SCROLL_SLOT_SIZE - 2,
)
matrices.pushPose()
matrices.translate(x + SCROLL_SLOT_SIZE / 2.0, y + 1.0, 0.0)
matrices.scale(2.5F, 2.5F, 1F)
val state = FloatingState()
state.currentAspects = renderablePokemon.aspects
drawProfilePokemon(
renderablePokemon = renderablePokemon,
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = state,
partialTicks = 0F,
scale = 4.5F
)
matrices.popPose()
context.disableScissor()
} else {
blitk(
matrixStack = matrices,
texture = unknownIcon,
x = x + 8.5,
y = y + 9,
width = 8,
height = 10
)
if (!species.implemented) {
blitk(
matrixStack = matrices,
texture = unimplementedIcon,
x = (x + 14) / SCALE,
y = (y + 15.5) / SCALE,
width = 7,
height = 7,
scale = SCALE
)
}
}
// Ensure elements are not hidden behind Pokémon render
matrices.pushPose()
matrices.translate(0.0, 0.0, 100.0)
drawScaledText(
context = context,
text = speciesNumber,
x = x + 1.5,
y = y + 2.5,
shadow = true,
scale = SCALE
)
if (discoveryLevel == PokedexEntryProgress.OWNED) {
blitk(
matrixStack = matrices,
texture = caughtIcon,
x = (x + 18) / SCALE,
y = (y + 1.5) / SCALE,
width = 11,
height = 11,
scale = SCALE
)
}
matrices.popPose()
}
}
}
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.EvolutionVisitor
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeEvolutionVisitor.RenderEvolutionData
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeRequirementVisitor.RenderRequirementData
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
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.cobblemonResource
import com.cobblemon.mod.common.util.itemRegistry
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
class EvolutionTreeEvolutionVisitor : EvolutionVisitor<RenderEvolutionData?> {
data class RenderEvolutionData(
val label: MutableComponent,
val icons: List<Item>,
val tooltips: List<MutableComponent>,
)
private val requirementVisitor = EvolutionTreeRequirementVisitor()
private fun visitRequirement(requirement: Requirement): RenderRequirementData? {
val icon = requirement.pokedexIcon?.let {
Minecraft.getInstance()?.player?.level()?.itemRegistry?.get(it)
}
val tooltip = requirement.pokedexTooltip?.let {
Component.translatable(it)
}
if (icon != null && tooltip != null) {
return RenderRequirementData(icon, tooltip)
}
return requirementVisitor.visit(requirement)
}
override fun visitBlockClickEvolution(blockClickEvolution: BlockClickEvolution): RenderEvolutionData? {
return null
}
override fun visitDummyEvolution(evolution: Evolution): RenderEvolutionData? {
return null
}
override fun visitItemInteractionEvolution(itemInteractionEvolution: ItemInteractionEvolution): RenderEvolutionData? {
val label = lang("ui.pokedex.evolution.item_interact.label").bold()
val item = itemInteractionEvolution.requiredContext.items.get().first().value()
val icons = mutableListOf(item)
val tooltips =
mutableListOf(lang("ui.pokedex.evolution.item_interact.tooltip", item.description.plainCopy().green()))
val requirementsDataList = itemInteractionEvolution.requirements.mapNotNull { requirement ->
visitRequirement(requirement)
}
requirementsDataList.forEach { requirement ->
icons.add(requirement.icon)
tooltips.add(requirement.tooltip)
}
return RenderEvolutionData(label, icons, tooltips)
}
override fun visitLevelUpEvolution(levelUpEvolution: LevelUpEvolution): RenderEvolutionData? {
val requirementsDataList = levelUpEvolution.requirements.map { requirement ->
visitRequirement(requirement)
}
val label = requirementsDataList.firstNotNullOfOrNull { requirement -> requirement?.label }
val icons = requirementsDataList.mapNotNull { requirementData -> requirementData?.icon }
val tooltips = requirementsDataList.mapNotNull { requirementData -> requirementData?.tooltip }
return RenderEvolutionData(label ?: Component.literal(""), icons, tooltips)
}
override fun visitTradeEvolution(tradeEvolution: TradeEvolution): RenderEvolutionData? {
val label = lang("ui.pokedex.evolution.trade.label")
val icons = mutableListOf<Item>(CobblemonItems.LINK_CABLE)
val tooltips = mutableListOf<MutableComponent>()
val species = tradeEvolution.requiredContext.species
if (species == null) {
tooltips.add(lang("ui.pokedex.evolution.trade.tooltip.with_any_species"))
} else {
PokemonSpecies.getByIdentifier(cobblemonResource(species))?.let {
tooltips.add(lang("ui.pokedex.evolution.trade.tooltip.with_species", it.translatedName.green()))
}
}
val requirementsDataList = tradeEvolution.requirements.mapNotNull { requirement ->
visitRequirement(requirement)
}
requirementsDataList.forEach { requirement ->
icons.add(requirement.icon)
tooltips.add(requirement.tooltip)
}
return RenderEvolutionData(label, icons, tooltips)
}
}
@@ -0,0 +1,271 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeRequirementVisitor.RenderRequirementData
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.requirement.RequirementVisitor
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.text.add
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.pokemon.requirements.*
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.world.item.Item
import net.minecraft.world.item.Items
class EvolutionTreeRequirementVisitor : RequirementVisitor<RenderRequirementData?> {
data class RenderRequirementData(
val icon: Item,
val tooltip: MutableComponent,
val label: MutableComponent? = null,
)
override fun visitAdvancementRequirement(advancementRequirement: AdvancementRequirement): RenderRequirementData? {
val icon = Items.BOOK
val advancementLanguageKey = advancementRequirement.requiredAdvancement.toLanguageKey()
val advancementComponent = Component.translatable("advancements.$advancementLanguageKey").green()
val tooltip = lang("ui.pokedex.requirement.advancement.tooltip", advancementComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitAnyRequirement(anyRequirement: AnyRequirement): RenderRequirementData? {
return null
}
override fun visitAreaRequirement(areaRequirement: AreaRequirement): RenderRequirementData? {
return null
}
override fun visitAttackDefenceRatioRequirement(attackDefenceRatioRequirement: AttackDefenceRatioRequirement): RenderRequirementData? {
return null
}
override fun visitBattleCriticalHitsRequirement(battleCriticalHitsRequirement: BattleCriticalHitsRequirement): RenderRequirementData? {
val icon = CobblemonItems.MEDICINAL_LEEK
val criticalsComponent = Component.literal(battleCriticalHitsRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.battle_critical_hits.tooltip", criticalsComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitBiomeRequirement(biomeRequirement: BiomeRequirement): RenderRequirementData? {
return null
}
override fun visitBlocksTraveledRequirement(blocksTraveledRequirement: BlocksTraveledRequirement): RenderRequirementData? {
val icon = Items.LEATHER_BOOTS
val blocksComponent = Component.literal(blocksTraveledRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.blocks_traveled.tooltip", blocksComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitDamageTakenRequirement(damageTakenRequirement: DamageTakenRequirement): RenderRequirementData? {
val icon = CobblemonItems.PUNCHING_GLOVE
val blocksComponent = Component.literal(damageTakenRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.damage_taken.tooltip", blocksComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitDefeatRequirement(defeatRequirement: DefeatRequirement): RenderRequirementData? {
val species = defeatRequirement.target.species?.let { PokemonSpecies.getByIdentifier(cobblemonResource(it)) } ?: return null
val icon = CobblemonItems.PUNCHING_GLOVE
val defeatedAmount = defeatRequirement.amount
val descriptionComponent = Component.literal(defeatedAmount.toString()).plainCopy().add(" ").add(species.translatedName).green()
val tooltip = lang("ui.pokedex.requirement.defeat.tooltip", descriptionComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitFriendshipRequirement(friendshipRequirement: FriendshipRequirement): RenderRequirementData? {
val icon = CobblemonItems.SOOTHE_BELL
val friendshipAmountComponent = Component.literal(friendshipRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.friendship.tooltip", friendshipAmountComponent)
val label = lang("ui.pokedex.requirement.friendship.label")
return RenderRequirementData(icon, tooltip, label)
}
override fun visitHeldItemRequirement(heldItemRequirement: HeldItemRequirement): RenderRequirementData? {
val item = heldItemRequirement.itemCondition.items.get().first().value()
val tooltip = lang("ui.pokedex.requirement.held_item.tooltip", item.description.plainCopy().green())
return RenderRequirementData(item, tooltip)
}
override fun visitLevelRequirement(levelRequirement: LevelRequirement): RenderRequirementData? {
val minLevel = levelRequirement.minLevel
val maxLevel = levelRequirement.maxLevel
val icon = CobblemonItems.RARE_CANDY
val tooltip =
if (minLevel == maxLevel || maxLevel == Int.MAX_VALUE)
lang("ui.pokedex.requirement.level.tooltip.min", Component.literal(minLevel.toString()).green())
else
lang("ui.pokedex.requirement.level.tooltip.between", Component.literal(minLevel.toString()).green(), Component.literal(maxLevel.toString()).green())
val label = lang("ui.pokedex.requirement.level.label", minLevel)
return RenderRequirementData(icon, tooltip, label)
}
override fun visitMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): RenderRequirementData? {
val icon = Items.CLOCK
val moonPhaseComponent = moonPhaseRequirement.moonPhase.displayName().green()
val tooltip = lang("ui.pokedex.requirement.moon_phase.tooltip", moonPhaseComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitMoveSetRequirement(moveSetRequirement: MoveSetRequirement): RenderRequirementData? {
val icon = CobblemonItems.PP_MAX
val tooltip = lang("ui.pokedex.requirement.has_move.tooltip", moveSetRequirement.move.displayName.green())
return RenderRequirementData(icon, tooltip)
}
override fun visitMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): RenderRequirementData? {
val type = ElementalTypes.get(moveTypeRequirement.type.name)
val icon = when (type) {
ElementalTypes.NORMAL -> CobblemonItems.NORMAL_GEM
ElementalTypes.FIRE -> CobblemonItems.FIRE_GEM
ElementalTypes.WATER -> CobblemonItems.WATER_GEM
ElementalTypes.GRASS -> CobblemonItems.GRASS_GEM
ElementalTypes.ELECTRIC -> CobblemonItems.ELECTRIC_GEM
ElementalTypes.ICE -> CobblemonItems.ICE_GEM
ElementalTypes.FIGHTING -> CobblemonItems.FIGHTING_GEM
ElementalTypes.POISON -> CobblemonItems.POISON_GEM
ElementalTypes.GROUND -> CobblemonItems.GROUND_GEM
ElementalTypes.FLYING -> CobblemonItems.FLYING_GEM
ElementalTypes.PSYCHIC -> CobblemonItems.PSYCHIC_GEM
ElementalTypes.BUG -> CobblemonItems.BUG_GEM
ElementalTypes.ROCK -> CobblemonItems.ROCK_GEM
ElementalTypes.GHOST -> CobblemonItems.GHOST_GEM
ElementalTypes.DRAGON -> CobblemonItems.DRAGON_GEM
ElementalTypes.DARK -> CobblemonItems.DARK_GEM
ElementalTypes.STEEL -> CobblemonItems.STEEL_GEM
ElementalTypes.FAIRY -> CobblemonItems.FAIRY_GEM
else -> CobblemonItems.NORMAL_GEM
}
val tooltip = lang("ui.pokedex.requirement.has_move_type.tooltip", moveTypeRequirement.type.displayName.green())
val label = lang("ui.pokedex.requirement.has_move_type.label")
return RenderRequirementData(icon, tooltip, label)
}
// TODO test
override fun visitOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): RenderRequirementData? {
val item = ownerHoldsItemRequirement.itemCondition.items.get().first().value()
val tooltip = lang("ui.pokedex.requirement.owner_held_item.tooltip", item.description.plainCopy().green())
return RenderRequirementData(item, tooltip)
}
override fun visitPartyMemberRequirement(partyMemberRequirement: PartyMemberRequirement): RenderRequirementData? {
return null
}
override fun visitPokemonPropertiesRequirement(pokemonPropertiesRequirement: PokemonPropertiesRequirement): RenderRequirementData? {
return null
}
override fun visitPropertyRangeRequirement(propertyRangeRequirement: PropertyRangeRequirement): RenderRequirementData? {
return null
}
override fun visitRecoilRequirement(recoilRequirement: RecoilRequirement): RenderRequirementData? {
val icon = CobblemonItems.LIFE_ORB
val recoilComponent = Component.literal(recoilRequirement.amount.toString()).green()
val tooltip = lang("ui.pokedex.requirement.recoil.tooltip", recoilComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStatCompareRequirement(statCompareRequirement: StatCompareRequirement): RenderRequirementData? {
val highStat = Stats.getStat(statCompareRequirement.highStat)
val lowStat = Stats.getStat(statCompareRequirement.lowStat)
val icon = when (highStat) {
Stats.HP, Stats.EVASION, Stats.ACCURACY -> CobblemonItems.HEALTH_MOCHI
Stats.ATTACK -> CobblemonItems.MUSCLE_MOCHI
Stats.DEFENCE -> CobblemonItems.RESIST_MOCHI
Stats.SPECIAL_ATTACK -> CobblemonItems.GENIUS_MOCHI
Stats.SPECIAL_DEFENCE -> CobblemonItems.CLEVER_MOCHI
Stats.SPEED -> CobblemonItems.SWIFT_MOCHI
}
val highStatComponent = highStat.displayName.plainCopy().green()
val lowStatComponent = lowStat.displayName.plainCopy().green()
val tooltip = lang("ui.pokedex.requirement.stat_compare.tooltip", highStatComponent, lowStatComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStatEqualRequirement(statEqualRequirement: StatEqualRequirement): RenderRequirementData? {
val statOne = Stats.getStat(statEqualRequirement.statOne)
val statTwo = Stats.getStat(statEqualRequirement.statTwo)
val statOneComponent = statOne.displayName.plainCopy().green()
val statTwoComponent = statTwo.displayName.plainCopy().green()
val icon = CobblemonItems.FRESH_START_MOCHI
val tooltip = lang("ui.pokedex.requirement.stat_equal.tooltip", statOneComponent, statTwoComponent)
return RenderRequirementData(icon, tooltip)
}
override fun visitStructureRequirement(structureRequirement: StructureRequirement): RenderRequirementData? {
return null
}
override fun visitTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): RenderRequirementData? {
val icon = Items.CLOCK
val timeRangeComponent = timeRangeRequirement.range.displayName() ?: return null
val tooltip = lang("ui.pokedex.requirement.time_range.tooltip", timeRangeComponent.green())
return RenderRequirementData(icon, tooltip)
}
override fun visitUseMoveRequirement(useMoveRequirement: UseMoveRequirement): RenderRequirementData? {
val icon = CobblemonItems.CHOICE_BAND
val tooltip = lang("ui.pokedex.requirement.use_move.tooltip", useMoveRequirement.move.displayName.green())
return RenderRequirementData(icon, tooltip)
return null
}
override fun visitWeatherRequirement(weatherRequirement: WeatherRequirement): RenderRequirementData? {
var icon: Item
var tooltip: MutableComponent
if (weatherRequirement.isThundering == true) {
icon = Items.LIGHTNING_ROD
tooltip = lang("ui.pokedex.requirement.weather.tooltip.thundering")
} else {
icon = Items.WATER_BUCKET
tooltip = lang("ui.pokedex.requirement.weather.tooltip.raining")
}
return RenderRequirementData(icon, tooltip)
}
override fun visitWorldRequirement(worldRequirement: WorldRequirement): RenderRequirementData? {
return null
}
}
@@ -0,0 +1,552 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.gui.*
import com.cobblemon.mod.common.api.pokedex.Dexes
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.text.add
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUI
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_DESCRIPTION_HEIGHT
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCROLL_SLOT_SIZE
import com.cobblemon.mod.common.client.gui.pokedex.ScaledButton
import com.cobblemon.mod.common.client.gui.pokedex.renderTooltip
import com.cobblemon.mod.common.client.gui.pokedex.widgets.PokemonSlotWidget
import com.cobblemon.mod.common.client.gui.pokedex.widgets.evolutiontree.EvolutionTreeEvolutionVisitor.RenderEvolutionData
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
class EvolutionTreeWidget(
val parent: PokedexGUI,
val pX: Int,
val pY: Int,
) : SoundlessWidget(
pX, pY,
HALF_OVERLAY_WIDTH,
POKEMON_DESCRIPTION_HEIGHT,
lang("ui.pokedex.pokemon_info")
) {
companion object {
private val slotResource = cobblemonResource("textures/gui/pokedex/pokedex_slot.png")
private val expandResource = cobblemonResource("textures/gui/pokedex/expand.png")
private val minimizeResource = cobblemonResource("textures/gui/pokedex/minimize.png")
const val X_MARGIN = 180
const val Y_MARGIN_MINIMIZED = 135
const val Y_MARGIN_EXPANDED = 53
const val EXPANDED_HEIGHT = 125
const val HORIZONTAL_PADDING = 38
const val VERTICAL_PADDING = 2
const val TREE_FORK_LENGTH = 4
const val ICON_X_PADDING = -4.0
const val ICON_Y_PADDING = -4.0
const val MILLIS_BETWEEN_ICONS_CYCLE = 1000
const val ICON_SLOT_BACKGROUND_SIZE = 8
const val ICON_SLOT_PADDING = 4
const val ICON_SLOT_HALF_PADDING = ICON_SLOT_PADDING / 2
const val LINE_COLOR = 0xff1d6b85.toInt()
const val EXPAND_BUTTON_X_MARGIN = 127f
const val EXPAND_BUTTON_Y_MARGIN = -10.5f
const val EXPAND_BUTTON_SIZE = 20
private var previousRootPokedexEntry: PokedexEntry? = null
private var previousRootPokedexForm: PokedexForm? = null
private val evolutionVisitor = EvolutionTreeEvolutionVisitor()
}
private var rootTreeDrawingNode: TreeDrawingNode<EvolutionNode>? = null
private var treeDrawingBounds: TreeDrawingBounds? = null
private var zoomLevel: Double = 0.0
private var panningX: Double = 0.0
private var panningY: Double = 0.0
private var hoveredTooltips: List<MutableComponent>? = null
private val expandButton: ScaledButton = ScaledButton(
0f,
0f,
EXPAND_BUTTON_SIZE,
EXPAND_BUTTON_SIZE,
resource = expandResource,
clickAction = {
parent.evolutionTreeExpanded = !parent.evolutionTreeExpanded
expandButton.resource = if (parent.evolutionTreeExpanded) minimizeResource else expandResource
updatePositioning()
}
).apply { addWidget(this) }
override fun renderWidget(
guiGraphics: GuiGraphics,
mouseX: Int,
mouseY: Int,
partialTick: Float,
) {
drawScaledText(
context = guiGraphics,
font = CobblemonResources.DEFAULT_LARGE,
text = Component.translatable("cobblemon.ui.pokedex.info.evolution_tree").bold(),
x = x + 9,
y = y - 10,
shadow = true
)
expandButton.render(guiGraphics, mouseX, mouseY, partialTick)
rootTreeDrawingNode?.let {
enableScissors(guiGraphics)
renderTreeDrawingNode(guiGraphics, it, mouseX, mouseY, partialTick)
guiGraphics.disableScissor()
hoveredTooltips?.let { tooltips ->
renderTooltip(
guiGraphics,
tooltips,
mouseX,
mouseY,
partialTick,
4,
)
}
hoveredTooltips = null
}
}
fun setup(pokedexEntry: PokedexEntry?, pokedexForm: PokedexForm?) {
if (pokedexEntry == null || pokedexForm == null) return
updatePositioning()
val (rootPokedexEntry, rootPokedexForm) = Dexes.findRootDexEntryBySpeciesId(pokedexEntry.speciesId, pokedexForm.displayForm)
val rootEvolutionNode = buildEvolutionTree(rootPokedexEntry, rootPokedexForm, null)
// val isSameEntry = previousRootPokedexEntry != null && pokedexEntry?.id == previousRootPokedexEntry?.id
// val isSameForm =
// previousRootPokedexForm != null && pokedexForm?.displayForm == previousRootPokedexForm?.displayForm
// TODO: figure out how to prevent pokedex from resetting all the widgets state
// if (isSameEntry && isSameForm) {
// return
// }
previousRootPokedexEntry = pokedexEntry
previousRootPokedexForm = pokedexForm
createDrawingTree(rootEvolutionNode).also {
rootTreeDrawingNode = it
treeDrawingBounds = calculateBounds<EvolutionNode>(it)
}
zoomLevel = 0.0
panningX = 0.0
panningY = 0.0
}
fun updatePositioning() {
x = pX + X_MARGIN
y = pY + if (parent.evolutionTreeExpanded) Y_MARGIN_EXPANDED else Y_MARGIN_MINIMIZED
height = if (parent.evolutionTreeExpanded) EXPANDED_HEIGHT else POKEMON_DESCRIPTION_HEIGHT
panningX = 0.0
panningY = 0.0
expandButton.buttonX = x + EXPAND_BUTTON_X_MARGIN
expandButton.buttonY = y + EXPAND_BUTTON_Y_MARGIN
}
private fun buildEvolutionTree(
pokedexEntry: PokedexEntry,
pokedexForm: PokedexForm,
evolution: Evolution? = null
): EvolutionNode {
val species = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId)!!
val formEquivalents = Dexes.getFormEquivalents(pokedexForm.displayForm)
val form = species.forms.firstOrNull { formEquivalents.contains(it.name.lowercase()) }
val parentSpecies = Dexes.findDexEntryBySpeciesId(species.resourceIdentifier)!!
val parentPokedexForm = parentSpecies.forms.first { formEquivalents.contains(it.displayForm.lowercase()) }
val aspects = evolution?.result?.aspects?.toMutableSet() ?: mutableSetOf()
form?.aspects?.let { aspects.addAll(it) }
val discoveryLevel = CobblemonClient.clientPokedexData.getHighestKnowledgeFor(pokedexEntry, pokedexForm, aspects)
val evolutions = form?.evolutions ?: species.evolutions
val drawData = evolution?.let { evolutionVisitor.visit(evolution) }
// TODO: figure out if this works for fakemon
val children = evolutions.mapNotNull { evolution ->
val speciesId = cobblemonResource(evolution.result.species!!)
val childPokedexEntry =
Dexes.findDexEntryBySpeciesId(speciesId)
if (childPokedexEntry == null) {
Cobblemon.LOGGER.warn("Dex entry not found for species: $speciesId")
return@mapNotNull null
}
val evolutionResult = evolution.result.create()
val formEquivalents = Dexes.getFormEquivalents(evolutionResult.form.name.lowercase())
val childPokedexForm = childPokedexEntry.forms.first { formEquivalents.contains(it.displayForm.lowercase()) }
return@mapNotNull buildEvolutionTree(childPokedexEntry, childPokedexForm, evolution)
}
return EvolutionNode(pokedexEntry, parentPokedexForm, aspects, discoveryLevel, children, drawData)
}
private fun renderTreeDrawingNode(
guiGraphics: GuiGraphics,
treeDrawingNode: TreeDrawingNode<EvolutionNode>,
mouseX: Int,
mouseY: Int,
delta: Float,
) {
val (treeX, treeY) = getDrawingCoordinates(treeDrawingNode)
if (treeDrawingNode.children.size == 1) {
val child = treeDrawingNode.children.first()
val (childX, _) = getDrawingCoordinates(child)
val lineStartX = treeX + SCROLL_SLOT_SIZE
val lineEndX = childX
val lineY = treeY + SCROLL_SLOT_SIZE / 2
child.value.renderData?.let { renderData ->
drawEvolutionInfo(
guiGraphics,
renderData,
lineStartX,
lineEndX,
lineY,
mouseX,
mouseY,
delta,
)
}
} else if (treeDrawingNode.children.size > 1) {
val treeForkStart = treeX + SCROLL_SLOT_SIZE
val treeForkEnd = treeX + SCROLL_SLOT_SIZE + TREE_FORK_LENGTH
val middleStart = treeY + SCROLL_SLOT_SIZE / 2
val (_, firstChildY) = getDrawingCoordinates(treeDrawingNode.children.first())
val (_, lastChildY) = getDrawingCoordinates(treeDrawingNode.children.last())
guiGraphics.hLine(
treeForkStart,
treeForkEnd,
middleStart,
LINE_COLOR,
)
guiGraphics.vLine(
treeForkEnd,
firstChildY + SCROLL_SLOT_SIZE / 2,
lastChildY + SCROLL_SLOT_SIZE / 2,
LINE_COLOR,
)
treeDrawingNode.children.forEach { child ->
val (childX, childY) = getDrawingCoordinates(child)
val lineStartX = treeForkEnd
val lineEndX = childX
val lineY = childY + SCROLL_SLOT_SIZE / 2
child.value.renderData?.let { renderData ->
drawEvolutionInfo(
guiGraphics,
renderData,
lineStartX,
lineEndX,
lineY,
mouseX,
mouseY,
delta,
)
}
}
}
treeDrawingNode.children.forEach { child ->
renderTreeDrawingNode(guiGraphics, child, mouseX, mouseY, delta)
}
val isVisible =
treeX >= x - SCROLL_SLOT_SIZE &&
treeX <= x + width &&
treeY >= y - SCROLL_SLOT_SIZE &&
treeY <= y + height
if (!isVisible) return
val evolutionNode = treeDrawingNode.value
val isSlotHovered =
isElementHovered(mouseX, mouseY, treeX, treeX + SCROLL_SLOT_SIZE, treeY, treeY + SCROLL_SLOT_SIZE)
val discoveryLevel = evolutionNode.pokedexEntryProgress
if (isSlotHovered) {
val text =
if (discoveryLevel == PokedexEntryProgress.UNREGISTERED) {
lang("ui.pokedex.unknown")
} else {
val species = PokemonSpecies.getByIdentifier(evolutionNode.pokedexEntry.speciesId)!!
val speciesComponent = species.translatedName
val formName = evolutionNode.pokedexForm.displayForm.lowercase()
val formComponent =
if (formName == "normal") null
else lang("ui.pokedex.info.form.${species}-${formName.replace("-", "")}")
formComponent?.add(" ")?.add(speciesComponent) ?: speciesComponent
}
guiGraphics.disableScissor()
renderTooltip(
context = guiGraphics,
text = text,
posX = mouseX,
posY = mouseY,
delta,
4,
)
enableScissors(guiGraphics)
}
val pokedexEntry = evolutionNode.pokedexEntry
val pokedexForm = evolutionNode.pokedexForm
val species = PokemonSpecies.getByIdentifier(evolutionNode.pokedexEntry.speciesId)!!
val encounteredForms = CobblemonClient.clientPokedexData.getEncounteredForms(pokedexEntry)
val formToRender = encounteredForms.firstOrNull { it.displayForm.equals(pokedexForm.displayForm, ignoreCase = true) }
val renderablePokemon =
if (formToRender != null) {
val seenGenders = CobblemonClient.clientPokedexData.getSeenGenders(pokedexEntry, formToRender)
val seenShinyStates = CobblemonClient.clientPokedexData.getSeenShinyStates(pokedexEntry, formToRender)
val aspectsToDraw = (pokedexEntry.displayAspects + evolutionNode.aspects).toMutableSet()
val formAspects = species.forms.firstOrNull { it.name.equals(formToRender.displayForm, ignoreCase = true) }?.aspects
if (formAspects != null) {
aspectsToDraw.addAll(formAspects)
}
if (seenGenders.contains(parent.gender)) {
aspectsToDraw.add(parent.gender.name.lowercase())
} else {
aspectsToDraw.add((seenGenders.firstOrNull() ?: Gender.GENDERLESS).name.lowercase())
}
if (parent.shiny && seenShinyStates.contains("shiny")) {
aspectsToDraw.add("shiny")
}
RenderablePokemon(species, aspectsToDraw)
} else {
null
}
PokemonSlotWidget.render(
context = guiGraphics,
x = treeX,
y = treeY,
isHovered = isSlotHovered,
species = species,
renderablePokemon = renderablePokemon,
discoveryLevel = discoveryLevel,
)
}
private fun drawEvolutionInfo(
guiGraphics: GuiGraphics,
renderData: RenderEvolutionData,
lineStartX: Int,
lineEndX: Int,
lineY: Int,
mouseX: Int,
mouseY: Int,
delta: Float,
) {
val lineXMiddle = (lineStartX + lineEndX) / 2
val iconX = (lineXMiddle + ICON_X_PADDING - ICON_SLOT_HALF_PADDING).toInt()
val iconY = (lineY + ICON_Y_PADDING - ICON_SLOT_HALF_PADDING).toInt()
val iconSize = ICON_SLOT_BACKGROUND_SIZE + ICON_SLOT_PADDING
val isVisible =
iconX >= x - iconSize &&
iconX <= x + width &&
iconY >= y - iconSize &&
iconY <= y + height
if (!isVisible) {
return
}
if (renderData.icons.isEmpty()) {
guiGraphics.hLine(
lineStartX,
lineEndX,
lineY,
LINE_COLOR,
)
} else {
guiGraphics.hLine(
lineStartX,
iconX - 1,
lineY,
LINE_COLOR,
)
guiGraphics.hLine(
iconX + iconSize,
lineEndX,
lineY,
LINE_COLOR,
)
blitk(
matrixStack = guiGraphics.pose(),
texture = slotResource,
x = iconX,
y = iconY,
width = iconSize,
height = iconSize,
)
val index = (System.currentTimeMillis() / MILLIS_BETWEEN_ICONS_CYCLE) % renderData.icons.size
val item = renderData.icons[index.toInt()]
renderScaledGuiItemIcon(
itemStack = item.defaultInstance,
x = lineXMiddle + ICON_X_PADDING,
y = lineY + ICON_Y_PADDING,
matrixStack = guiGraphics.pose(),
scale = PokedexGUIConstants.SCALE.toDouble(),
)
}
val isLineHovered = isElementHovered(mouseX, mouseY, lineStartX, lineEndX, lineY - 1, lineY + 1)
val isIconHovered = isElementHovered(
mouseX,
mouseY,
iconX.toInt(),
iconX.toInt() + iconSize,
iconY.toInt(),
iconY.toInt() + iconSize,
)
if (renderData.tooltips.isNotEmpty() &&
(isLineHovered || isIconHovered) &&
this.isHovered(mouseX.toDouble(), mouseY.toDouble())
) {
hoveredTooltips = renderData.tooltips
}
}
private fun getDrawingCoordinates(node: TreeDrawingNode<EvolutionNode>): Pair<Int, Int> {
val halfSlot = SCROLL_SLOT_SIZE / 2f
val xStep = halfSlot + HORIZONTAL_PADDING
val yStep = halfSlot + VERTICAL_PADDING
// Swaps the x and y to draw the tree horizontally
val xDislocation = (node.y - treeDrawingBounds!!.yCenter) * xStep
val yDislocation = (node.x - treeDrawingBounds!!.xCenter) * yStep
val xCenter = width / 2f - halfSlot
val yCenter = height / 2f - halfSlot
val screenX = (xCenter.toInt() + xDislocation.toInt() + panningX.toInt() + x)
val screenY = (yCenter.toInt() + yDislocation.toInt() + panningY.toInt() + y)
return screenX to screenY
}
private fun isElementHovered(
mouseX: Int,
mouseY: Int,
startX: Int,
endX: Int,
startY: Int,
endY: Int,
): Boolean {
return mouseX >= startX && mouseX <= endX && mouseY >= startY && mouseY <= endY
}
override fun mouseDragged(
mouseX: Double,
mouseY: Double,
button: Int,
deltaX: Double,
deltaY: Double
): Boolean {
panningX += deltaX
panningY += deltaY
val bounds = treeDrawingBounds ?: return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
val treeHeight = bounds.height.coerceAtLeast(1)
val treeWidth = bounds.width.coerceAtLeast(1)
val xStep = HORIZONTAL_PADDING + SCROLL_SLOT_SIZE / 2.0
val yStep = VERTICAL_PADDING + SCROLL_SLOT_SIZE / 2.0
val minPanningX = (treeHeight - 1) * -xStep / 2.0 - (width + SCROLL_SLOT_SIZE) / 2.0
val maxPanningX = (treeHeight - 1) * xStep / 2.0 + (width + SCROLL_SLOT_SIZE) / 2.0
val divideBy = if (treeWidth % 2 == 0) 4.0 else 2.0
val minPanningY = (treeWidth - 1) * -yStep / 2.0 - height / 2.0 + SCROLL_SLOT_SIZE / divideBy
val maxPanningY = (treeWidth - 1) * yStep / 2.0 + height / 2.0 - SCROLL_SLOT_SIZE / divideBy
panningX = panningX.coerceIn(minPanningX, maxPanningX)
panningY = panningY.coerceIn(minPanningY, maxPanningY)
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
}
fun isHovered(mouseX: Double, mouseY: Double): Boolean {
return mouseX.toInt() in x..(x + width) && mouseY.toInt() in y..(y + height)
}
fun enableScissors(guiGraphics: GuiGraphics) {
guiGraphics.enableScissor(x + 1, y, x + width - 1, y + height)
}
private class EvolutionNode(
val pokedexEntry: PokedexEntry,
val pokedexForm: PokedexForm,
val aspects: Set<String>,
val pokedexEntryProgress: PokedexEntryProgress,
override val children: List<EvolutionNode>,
val renderData: RenderEvolutionData?,
) : TreeNode<EvolutionNode>
}
@@ -22,6 +22,8 @@ object ServerSettingsPacketHandler : ClientNetworkPacketHandler<ServerSettingsPa
ServerSettings.maxPokemonFriendship = packet.maxPokemonFriendship
ServerSettings.maxDynamaxLevel = packet.maxDynamaxLevel
ServerSettings.unlockAllMoveDexMovesByDefault = packet.unlockAllMoveDexMovesByDefault
ServerSettings.pokemonIntrinsicSizeMin = packet.pokemonIntrinsicSizeMin
ServerSettings.pokemonIntrinsicSizeMax = packet.pokemonIntrinsicSizeMax
}
}
@@ -1,121 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WaveAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WaveSegment
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ArbokModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("arbok")
override val head = getPart("head_ai")
override var portraitScale = 1.5F
override var portraitTranslation = Vec3(-0.4, 1.0, 0.0)
override var profileScale = 0.67F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var sleep: Pose
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var summary: Pose
val tail = getPart("tail")
val tail2 = getPart("tail2")
val tail3 = getPart("tail3")
val tail4 = getPart("tail4")
val tail5 = getPart("tail5")
val tailWaveSegment = WaveSegment(modelPart = tail, length = 11F)
val tail2WaveSegment = WaveSegment(modelPart = tail2, length = 11F)
val tail3WaveSegment = WaveSegment(modelPart = tail3, length = 11F)
val tail4WaveSegment = WaveSegment(modelPart = tail4, length = 11F)
val tail5WaveSegment = WaveSegment(modelPart = tail5, length = 11F)
override val cryAnimation = CryProvider { bedrockStateful("arbok", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("arbok", "blink") }
// TODO tongue_flick
val wave = WaveAnimation(
waveFunction = sineFunction(
period = 10F,
amplitude = 0.5F
),
basedOnLimbSwing = true,
oscillationsScalar = 8F,
head = tail,
rotationAxis = ModelPartTransformation.Y_AXIS,
motionAxis = ModelPartTransformation.X_AXIS,
headLength = 0.1F,
segments = arrayOf(
tailWaveSegment,
tail2WaveSegment,
tail3WaveSegment,
tail4WaveSegment,
tail5WaveSegment
)
)
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("arbok", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("arbok", "summary_idle"),
wave
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("arbok", "ground_walk"),
wave
)
)
summary = registerPose(
poseName = "summary",
poseTypes = UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("arbok", "summary_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, sleep)) bedrockStateful("arbok", "faint") else null
}
@@ -1,74 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class DittoModel(root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("ditto")
override var portraitScale = 3.2F
override var portraitTranslation = Vec3(0.0, -2.2, 0.0)
override var profileScale = 1.4F
override var profileTranslation = Vec3(0.0, -0.34, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
override val cryAnimation = CryProvider { bedrockStateful("ditto", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("ditto", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
// singleBoneLook()
bedrock("ditto", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
// singleBoneLook()
bedrock("ditto", "ground_walk")
)
)
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
// singleBoneLook()
bedrock("ditto", "sleep")
)
)
}
override fun getFaintAnimation(state: PosableState) = bedrockStateful("ditto", "faint")
}
@@ -1,103 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class OmanyteModel(root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("omanyte")
override var portraitScale = 3.15F
override var portraitTranslation = Vec3(-0.06, -3.18, 0.0)
override var profileScale = 1.13F
override var profileTranslation = Vec3(0.0, -0.02, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var float: CobblemonPose
lateinit var swim: CobblemonPose
lateinit var sleep: CobblemonPose
lateinit var battleidle: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("omanyte", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("omanyte", "blink") }
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("omanyte", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STANDING_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
transformTicks = 10,
condition = { !it.isBattling},
animations = arrayOf(
bedrock("omanyte", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES - PoseType.SWIM,
quirks = arrayOf(blink),
transformTicks = 10,
animations = arrayOf(
bedrock("omanyte", "ground_walk")
)
)
float = registerPose(
poseName = "float",
poseTypes = setOf(PoseType.FLOAT, PoseType.HOVER),
quirks = arrayOf(blink),
transformTicks = 10,
animations = arrayOf(
bedrock("omanyte", "water_idle")
)
)
swim = registerPose(
poseName = "swim",
poseTypes = setOf(PoseType.SWIM, PoseType.FLY),
quirks = arrayOf(blink),
transformTicks = 10,
animations = arrayOf(
bedrock("omanyte", "water_swim")
)
)
battleidle = registerPose(
poseName = "battle-standing",
poseTypes = PoseType.STATIONARY_POSES,
quirks = arrayOf(blink),
transformTicks = 10,
condition = { it.isBattling},
animations = arrayOf(
bedrock("omanyte", "battle_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("omanyte", "faint") else null
}
@@ -1,102 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class OmastarModel(root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("omastar")
override var portraitTranslation = Vec3(0.02, -2.20, 0.0)
override var portraitScale = 2.4F
override var profileTranslation = Vec3(0.0, 0.066, 0.0)
override var profileScale = 1.1F
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var float: CobblemonPose
lateinit var swim: CobblemonPose
lateinit var sleep: CobblemonPose
lateinit var battleidle: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("omastar", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("omastar", "blink") }
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("omastar", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STANDING_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
transformTicks = 10,
condition = { !it.isBattling},
animations = arrayOf(
bedrock("omastar", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES - PoseType.SWIM,
quirks = arrayOf(blink),
transformTicks = 10,
animations = arrayOf(
bedrock("omastar", "ground_walk")
)
)
float = registerPose(
poseName = "float",
poseTypes = setOf(PoseType.FLOAT, PoseType.HOVER),
quirks = arrayOf(blink),
transformTicks = 10,
animations = arrayOf(
bedrock("omastar", "water_idle")
)
)
swim = registerPose(
poseName = "swim",
poseTypes = setOf(PoseType.SWIM, PoseType.FLY),
quirks = arrayOf(blink),
transformTicks = 10,
animations = arrayOf(
bedrock("omastar", "water_swim")
)
)
battleidle = registerPose(
poseName = "battle-standing",
poseTypes = PoseType.STATIONARY_POSES,
quirks = arrayOf(blink),
transformTicks = 10,
condition = { it.isBattling},
animations = arrayOf(
bedrock("omastar", "battle_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("omastar", "faint") else null
}
@@ -1,155 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import com.cobblemon.mod.common.util.isUnderWater
import com.cobblemon.mod.common.util.isInWater
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class FeraligatrModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame {
override val rootPart = root.registerChildWithAllChildren("feraligatr")
override val head = getPart("head_ai")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 1.3F
override var portraitTranslation = Vec3(-0.7, 1.1, 0.0)
override var profileScale = 0.6F
override var profileTranslation = Vec3(0.0, 0.8, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var floating: Pose
lateinit var swimming: Pose
lateinit var sleep: Pose
lateinit var watersleep: Pose
lateinit var battleidle: Pose
lateinit var water_surface_idle: Pose
lateinit var water_surface_swim: Pose
val wateroffset = -10
override val cryAnimation = CryProvider { bedrockStateful("feraligatr", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("feraligatr", "blink")}
sleep = registerPose(
poseName = "sleeping",
poseType = PoseType.SLEEP,
condition = { !it.isInWater },
animations = arrayOf(bedrock("feraligatr", "sleep"))
)
watersleep = registerPose(
poseName = "water_sleeping",
poseType = PoseType.SLEEP,
condition = { it.isInWater },
animations = arrayOf(bedrock("feraligatr", "water_sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STAND,
transformTicks = 10,
condition = { !it.isBattling && !it.isInWater && !it.isUnderWater },
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("feraligatr", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
transformTicks = 10,
poseType = PoseType.WALK,
condition = { !it.isInWater && !it.isUnderWater },
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("feraligatr", "ground_walk")
)
)
floating = registerPose(
poseName = "floating",
transformTicks = 10,
poseType = PoseType.FLOAT,
condition = { it.isUnderWater },
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("feraligatr", "water_idle")
)
)
swimming = registerPose(
poseName = "swimming",
transformTicks = 10,
condition = { it.isUnderWater },
poseType = PoseType.SWIM,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("feraligatr", "water_swim"),
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling && !it.isInWater },
animations = arrayOf(
singleBoneLook(),
bedrock("feraligatr", "battle_idle")
)
)
water_surface_idle = registerPose(
poseName = "surface_idle",
poseTypes = PoseType.STATIONARY_POSES,
quirks = arrayOf(blink),
condition = { !it.isUnderWater && it.isInWater },
animations = arrayOf(
singleBoneLook(),
bedrock("feraligatr", "watersurface_idle"),
),
transformedParts = arrayOf(rootPart.createTransformation().addPosition(ModelPartTransformation.Y_AXIS, wateroffset))
)
water_surface_swim = registerPose(
poseName = "surface_swim",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
condition = { !it.isUnderWater && it.isInWater },
animations = arrayOf(
singleBoneLook(),
bedrock("feraligatr", "watersurface_swim"),
),
transformedParts = arrayOf(rootPart.createTransformation().addPosition(ModelPartTransformation.Y_AXIS, wateroffset))
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, battleidle, sleep)) bedrockStateful("feraligatr", "faint") else if (state.isPosedIn(water_surface_idle, water_surface_swim, watersleep )) bedrockStateful("feraligatr", "faint") else null
}
@@ -1,91 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class SmoochumModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("smoochum")
override val head = getPart("head")
override var portraitScale = 2.3F
override var portraitTranslation = Vec3(-0.14, -1.0, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var shoulderLeft: Pose
lateinit var shoulderRight: Pose
val shoulderOffset = 1
override fun registerPoses() {
// val blink = quirk { bedrockStateful("smoochum", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
// quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("smoochum", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
// quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("smoochum", "ground_idle")
)
)
shoulderLeft = registerPose(
poseType = PoseType.SHOULDER_LEFT,
//quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("smoochum", "ground_idle")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, shoulderOffset)
)
)
shoulderRight = registerPose(
poseType = PoseType.SHOULDER_RIGHT,
//quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("smoochum", "ground_idle")
),
transformedParts = arrayOf(
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, -shoulderOffset)
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("smoochum", "faint") else null
}
@@ -19,7 +19,7 @@ import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class TyphlosionHisuianModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("typhlosion_hisui")
override val rootPart = root.registerChildWithAllChildren("typhlosion")
override val head = getPart("head")
override var portraitScale = 1.4F
@@ -1,67 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class TyranitarModel(root: ModelPart) : PokemonPosableModel(root), BipedFrame, BimanualFrame, HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("tyranitar")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 1.21F
override var portraitTranslation = Vec3(-0.43, 3.73, 0.0)
override var profileScale = 0.33F
override var profileTranslation = Vec3(0.02, 1.31, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
override val cryAnimation = CryProvider { bedrockStateful("tyranitar", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("tyranitar", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(pitchMultiplier = 0.2F, yawMultiplier = 0.4F),
bedrock("tyranitar", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(pitchMultiplier = 0.2F, yawMultiplier = 0.4F),
bedrock("tyranitar", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
)
)
}
}
@@ -23,7 +23,7 @@ import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class WooperPaldeanModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("wooper_paldean")
override val rootPart = root.registerChildWithAllChildren("wooper")
override val head = getPart("head")
override var portraitScale = 2.0F
@@ -1,78 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen3
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class LuvdiscModel (root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("luvdisc")
override var portraitScale = 6.0F
override var portraitTranslation = Vec3(0.15, -6.5, 0.0)
override var profileScale = 2.0F
override var profileTranslation = Vec3(0.0, -1.3, 0.0)
lateinit var standing: Pose
lateinit var sleep: Pose
lateinit var walk: Pose
lateinit var float: Pose
lateinit var swim: Pose
override fun registerPoses() {
val blink = quirk { bedrockStateful("luvdisc", "blink")}
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("luvdisc", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseType = PoseType.STAND,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("luvdisc", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseType = PoseType.WALK,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("luvdisc", "ground_walk")
)
)
float = registerPose(
poseName = "float",
poseTypes = PoseType.UI_POSES + PoseType.FLOAT,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("luvdisc", "water_idle")
)
)
swim = registerPose(
poseName = "swim",
poseType = PoseType.SWIM,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("luvdisc", "water_swim")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, sleep)) bedrockStateful("luvdisc", "ground_faint") else null
}
@@ -1,170 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.FLYING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.SHOULDER_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ChatotModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BiWingedFrame{
override val rootPart = root.registerChildWithAllChildren("chatot")
override val leftWing = getPart("wing_left")
override val rightWing = getPart("wing_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val head = getPart("head")
private val tail = getPart("tail")
override var portraitScale = 3.5F
override var portraitTranslation = Vec3(-0.1, -2.1, 0.0)
override var profileScale = 1.2F
override var profileTranslation = Vec3(0.0, -0.01, 0.0)
lateinit var sleep: Pose
lateinit var stand: Pose
lateinit var walk: Pose
lateinit var fly: Pose
override val cryAnimation = CryProvider { bedrockStateful("chatot", "cry") }
override fun registerPoses() {
// no sleep anim yet
// sleep = registerPose(
// poseType = PoseType.SLEEP,
// animations = arrayOf(bedrock("chatot", "sleep"))
// )
val blink = quirk { bedrockStateful("chatot", "blink") }
stand = registerPose(
poseName = "standing",
poseTypes = SHOULDER_POSES + UI_POSES + PoseType.STAND,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("chatot", "ground_idle")
)
)
fly = registerPose(
poseName = "hover",
poseTypes = FLYING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("chatot", "air_idle"),
WingFlapIdleAnimation(this,
flapFunction = sineFunction(verticalShift = -10F.toRadians(), period = 0.9F, amplitude = 0.6F),
timeVariable = { state, _, _ -> state.animationSeconds },
axis = ModelPartTransformation.Z_AXIS
)
)
)
walk = registerPose(
poseName = "walking",
poseType = PoseType.WALK,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("chatot", "ground_idle"),
rootPart.translation(
function = parabolaFunction(
peak = -4F,
period = 0.4F
),
timeVariable = { state, _, _ -> state.animationSeconds },
axis = ModelPartTransformation.Y_AXIS
),
head.translation(
function = sineFunction(
amplitude = (-20F).toRadians(),
period = 1F,
verticalShift = (-10F).toRadians()
),
axis = ModelPartTransformation.X_AXIS,
timeVariable = { state, _, _ -> state.animationSeconds }
),
leftLeg.rotation(
function = parabolaFunction(
tightness = -20F,
phaseShift = 0F,
verticalShift = (30F).toRadians()
),
axis = ModelPartTransformation.X_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
rightLeg.rotation(
function = parabolaFunction(
tightness = -20F,
phaseShift = 0F,
verticalShift = (30F).toRadians()
),
axis = ModelPartTransformation.X_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
tail.rotation(
function = sineFunction(
amplitude = (-5F).toRadians(),
period = 1F
),
axis = ModelPartTransformation.X_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
wingFlap(
flapFunction = sineFunction(
amplitude = (-5F).toRadians(),
period = 0.4F,
phaseShift = 0.00F,
verticalShift = (-20F).toRadians()
),
timeVariable = { state, _, _ -> state.animationSeconds },
axis = ModelPartTransformation.Z_AXIS
),
rightWing.translation(
function = parabolaFunction(
tightness = -10F,
phaseShift = 30F,
verticalShift = (25F).toRadians()
),
axis = ModelPartTransformation.Y_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
leftWing.translation(
function = parabolaFunction(
tightness = -10F,
phaseShift = 30F,
verticalShift = (25F).toRadians()
),
axis = ModelPartTransformation.Y_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
),
)
)
}
}
@@ -1,86 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen7
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class TurtonatorModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("turtonator")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 1.62F
override var portraitTranslation = Vec3(-1.14, 1.92, 0.0)
override var profileScale = 0.54F
override var profileTranslation = Vec3(-0.08, 0.87, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var battleidle: CobblemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("turtonator", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("turtonator", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("turtonator", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
//bedrock("turtonator", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("turtonator", "battle_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("turtonator", "faint") else null
}
@@ -248,10 +248,8 @@ object VaryingModelRepository {
inbuilt("machop", ::MachopModel)
inbuilt("machoke", ::MachokeModel)
inbuilt("machamp", ::MachampModel)
inbuilt("arbok", ::ArbokModel)
inbuilt("chansey", ::ChanseyModel)
inbuilt("cubone", ::CuboneModel)
inbuilt("ditto", ::DittoModel)
inbuilt("dodrio", ::DodrioModel)
inbuilt("doduo", ::DoduoModel)
inbuilt("electabuzz", ::ElectabuzzModel)
@@ -278,8 +276,6 @@ object VaryingModelRepository {
inbuilt("nidoranm", ::NidoranmModel)
inbuilt("nidorina", ::NidorinaModel)
inbuilt("nidorino", ::NidorinoModel)
inbuilt("omanyte", ::OmanyteModel)
inbuilt("omastar", ::OmastarModel)
inbuilt("persian", ::PersianModel)
inbuilt("pinsir", ::PinsirModel)
inbuilt("poliwag", ::PoliwagModel)
@@ -293,7 +289,6 @@ object VaryingModelRepository {
inbuilt("venomoth", ::VenomothModel)
inbuilt("venonat", ::VenonatModel)
inbuilt("elekid", ::ElekidModel)
inbuilt("smoochum", ::SmoochumModel)
inbuilt("hitmontop", ::HitmontopModel)
inbuilt("electivire", ::ElectivireModel)
inbuilt("tangrowth", ::TangrowthModel)
@@ -355,7 +350,6 @@ object VaryingModelRepository {
inbuilt("whismur", :: WhismurModel)
inbuilt("loudred", :: LoudredModel)
inbuilt("exploud", :: ExploudModel)
inbuilt("luvdisc", :: LuvdiscModel)
inbuilt("cryogonal", :: CryogonalModel)
inbuilt("pumpkaboo", :: PumpkabooModel)
inbuilt("gourgeist", :: GourgeistModel)
@@ -397,7 +391,6 @@ object VaryingModelRepository {
inbuilt("tandemaus", ::TandemausModel)
inbuilt("fidough", ::FidoughModel)
inbuilt("dachsbun", ::DachsbunModel)
inbuilt("chatot", ::ChatotModel)
inbuilt("gligar", ::GligarModel)
inbuilt("gliscor", ::GliscorModel)
inbuilt("poochyena", ::PoochyenaModel)
@@ -487,7 +480,6 @@ object VaryingModelRepository {
inbuilt("phantump", ::PhantumpModel)
inbuilt("totodile", ::TotodileModel)
inbuilt("croconaw", ::CroconawModel)
inbuilt("feraligatr", ::FeraligatrModel)
inbuilt("cyndaquil", ::CyndaquilModel)
inbuilt("quilava", ::QuilavaModel)
inbuilt("typhlosion", ::TyphlosionModel)
@@ -544,7 +536,6 @@ object VaryingModelRepository {
inbuilt("petilil_hisui_bias", ::PetililHisuiBiasModel)
inbuilt("lilligant_hisuian", ::LilligantHisuianModel)
inbuilt("darumaka", ::DarumakaModel)
inbuilt("turtonator", ::TurtonatorModel)
inbuilt("cufant", ::CufantModel)
inbuilt("copperajah", ::CopperajahModel)
inbuilt("budew", ::BudewModel)
@@ -574,7 +565,6 @@ object VaryingModelRepository {
inbuilt("vibrava", ::VibravaModel)
inbuilt("larvitar", ::LarvitarModel)
inbuilt("pupitar", ::PupitarModel)
inbuilt("tyranitar", ::TyranitarModel)
inbuilt("impidimp", ::ImpidimpModel)
inbuilt("morgrem", ::MorgremModel)
inbuilt("grimmsnarl", ::GrimmsnarlModel)
@@ -28,5 +28,7 @@ object ServerSettings {
var maxPokemonFriendship = Cobblemon.config.maxPokemonFriendship
var maxDynamaxLevel = Cobblemon.config.maxDynamaxLevel
var unlockAllMoveDexMovesByDefault = Cobblemon.config.unlockAllMoveDexMovesByDefault
var pokemonIntrinsicSizeMin = Cobblemon.config.pokemonIntrinsicSizeMin
var pokemonIntrinsicSizeMax = Cobblemon.config.pokemonIntrinsicSizeMax
}
@@ -243,18 +243,6 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Pokemon, lang = "pokemon_intrinsic_size_max", SERVER)
var pokemonIntrinsicSizeMax = 1.05F
@CobblemonConfigField(Category.Pokemon, lang = "alpha_pokemon_size_small_multiplier", SERVER)
var alphaPokemonSizeSmallMultiplier = 1.70F
@CobblemonConfigField(Category.Pokemon, lang = "alpha_pokemon_size_medium_multiplier", SERVER)
var alphaPokemonSizeMediumMultiplier = 1.55F
@CobblemonConfigField(Category.Pokemon, lang = "alpha_pokemon_size_large_multiplier", SERVER)
var alphaPokemonSizeLargeMultiplier = 1.40F
@CobblemonConfigField(Category.Pokemon, lang = "alpha_pokemon_size_extra_large_multiplier", SERVER)
var alphaPokemonSizeExtraLargeMultiplier = 1.25F
@CobblemonConfigField(Category.Pokemon, lang = "baby_pokemon_level_duration", SERVER)
var babyPokemonLevelDuration = 9
@@ -347,9 +335,6 @@ class CobblemonConfig {
// @CobblemonConfigField(Category.Riding, lang = "third_person_view_bobbing", CLIENT)
var thirdPersonViewBobbing = true
@CobblemonConfigField(Category.Riding, lang = "invert_roll", CLIENT)
var invertRoll = false
@CobblemonConfigField(Category.Riding, lang = "invert_pitch", CLIENT)
var invertPitch = false
@@ -365,9 +350,6 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Riding, lang = "swap_x_and_y_axes", CLIENT)
var swapXAndYAxes = false
@CobblemonConfigField(Category.Riding, lang = "automatic_righting_delay", CLIENT)
var rightingDelay = -1.0
@CobblemonConfigField(Category.Riding, lang = "disable_roll", CLIENT)
var disableRoll = false
@@ -798,6 +798,13 @@ open class PokemonEntity(
return pokemon.isFireImmune()
}
/**
* Prevents ice type Pokémon from freezing (from powered snow)
*/
override fun canFreeze(): Boolean {
return !pokemon.isFreezeImmune() && super.canFreeze()
}
/**
* Prevents flying type Pokémon from taking fall damage.
*/
@@ -26,7 +26,9 @@ class ServerSettingsPacket internal constructor(
val maxPokemonLevel: Int,
val maxPokemonFriendship: Int,
val maxDynamaxLevel: Int,
val unlockAllMoveDexMovesByDefault: Boolean
val unlockAllMoveDexMovesByDefault: Boolean,
val pokemonIntrinsicSizeMin: Float,
val pokemonIntrinsicSizeMax: Float
) : NetworkPacket<ServerSettingsPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
@@ -37,9 +39,14 @@ class ServerSettingsPacket internal constructor(
buffer.writeInt(Cobblemon.config.maxPokemonFriendship)
buffer.writeInt(Cobblemon.config.maxDynamaxLevel)
buffer.writeBoolean(Cobblemon.config.unlockAllMoveDexMovesByDefault)
buffer.writeFloat(Cobblemon.config.pokemonIntrinsicSizeMin)
buffer.writeFloat(Cobblemon.config.pokemonIntrinsicSizeMax)
}
companion object {
val ID = cobblemonResource("server_settings")
fun decode(buffer: RegistryFriendlyByteBuf) = ServerSettingsPacket(buffer.readBoolean(), buffer.readBoolean(), buffer.readBoolean(), buffer.readInt(), buffer.readInt(), buffer.readInt(), buffer.readBoolean())
fun decode(buffer: RegistryFriendlyByteBuf) = ServerSettingsPacket(buffer.readBoolean(),
buffer.readBoolean(), buffer.readBoolean(),
buffer.readInt(), buffer.readInt(), buffer.readInt(),
buffer.readBoolean(), buffer.readFloat(), buffer.readFloat())
}
}
@@ -1037,6 +1037,10 @@ open class Pokemon : ShowdownIdentifiable {
return ElementalTypes.FIRE in types || form.behaviour.moving.swim.canSwimInLava || form.behaviour.fireImmune
}
fun isFreezeImmune(): Boolean {
return ElementalTypes.ICE in types || form.behaviour.freezeImmune
}
fun dampensVibrations(): Boolean = form.behaviour.dampensVibrations
// function to return the max hunger for the pokemon
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.pokemon
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.client.settings.ServerSettings
enum class PokemonSizeCategory {
XS,
@@ -21,7 +21,7 @@ enum class PokemonSizeCategory {
// Find which size category corresponds to the given scale modifier.
// The scale modifier should be between the intrinsic min and max size.
fun fromScale(scaleModifier: Float): PokemonSizeCategory {
val config = Cobblemon.config
val config = ServerSettings //Don't use cobblemon config here as it will be used by server AND client
val minScale = config.pokemonIntrinsicSizeMin
val maxScale = config.pokemonIntrinsicSizeMax
val range = (maxScale - minScale).coerceAtLeast(0.0001F)
@@ -35,6 +35,9 @@ class FormPokemonBehaviour {
@SerializedName("fireImmune")
private val _fireImmune: Boolean? = null
@SerializedName("freezeImmune")
private val _freezeImmune: Boolean? = null
@SerializedName("dampensVibrations")
private val _dampensVibrations: Boolean? = null
@@ -72,6 +75,9 @@ class FormPokemonBehaviour {
val fireImmune: Boolean
get() = _fireImmune ?: parent.fireImmune
val freezeImmune: Boolean
get() = _freezeImmune ?: parent.freezeImmune
val entityInteract: EntityBehaviour
get() = _entityInteract ?: parent.entityInteract
@@ -318,7 +318,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
// Hitbox thing looks confusing but if the hitbox volume is more than like, 5, it starts getting pretty
// fucking slow to use the findAcceptedNodeWalk function
val strictlyWalkPathing = !canFly() && !mob.isInWater && mob.boundingBox.size < MAX_HITBOX_SIZE_FOR_WALKING
val strictlyWalkPathing = !canFly() && !mob.isInWater
val doVerticalNeighbourChecks = (canFly() || mob.isInWater) && mob.boundingBox.size < MAX_HITBOX_FOR_VERTICAL_NEIGHBOURS
// Non-diagonal surroundings in 3d space
@@ -623,9 +623,11 @@ class OmniPathNodeMaker : NodeEvaluator() {
override fun getPathTypeOfMob(pfContext: PathfindingContext, x: Int, y: Int, z: Int, mob: Mob): PathType {
val set = EnumSet.noneOf(PathType::class.java)
val sizeX = (mob.boundingBox.maxX - mob.boundingBox.minX).toInt() + 1
val sizeY = (mob.boundingBox.maxY - mob.boundingBox.minY).toInt() + 1
val sizeZ = (mob.boundingBox.maxZ - mob.boundingBox.minZ).toInt() + 1
// Capping the observed size of hitboxes here to put an upper limit on the cost of larger hitbox mobs
// Mobs larger than these caps will inevitably become stuck on obstacles as their pathing will be flawed
val sizeX = ((mob.boundingBox.maxX - mob.boundingBox.minX).toInt() + 1).coerceAtMost(2)
val sizeY = ((mob.boundingBox.maxY - mob.boundingBox.minY).toInt() + 1).coerceAtMost(3)
val sizeZ = ((mob.boundingBox.maxZ - mob.boundingBox.minZ).toInt() + 1).coerceAtMost(2)
// TODO -- This is experimental code to see if this is meaningful. We should clean this up later when time permits.
val returnedEarlyPathType = mutableListOf<PathType>()
@@ -31,6 +31,7 @@ open class PokemonBehaviour(
val herd: HerdBehaviour = HerdBehaviour(),
val characteristicRainbow: Boolean = false,
val itemInteract: ItemBehavior = ItemBehavior(),
val freezeImmune: Boolean = false,
) {
@Transient
val struct = ObjectValue<PokemonBehaviour>(this).also {
@@ -22,7 +22,7 @@ import net.minecraft.world.entity.player.Player
*
* @author whatsy
*/
class AdvancementRequirement(val requiredAdvancement: ResourceLocation) : OwnerQueryRequirement {
class AdvancementRequirement(val requiredAdvancement: ResourceLocation) : OwnerQueryRequirement() {
override fun checkPlayer(
pokemon: Pokemon,
@@ -16,7 +16,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
*
* @property possibilities A collection of possible [Requirement]s that can allow this requirement to be valid.
*/
class AnyRequirement(val possibilities: Collection<Requirement>) : Requirement {
class AnyRequirement(val possibilities: Collection<Requirement>) : Requirement() {
override fun check(pokemon: Pokemon) = this.possibilities.any { it.check(pokemon) }
companion object {
const val ADAPTER_VARIANT = "any"
@@ -21,7 +21,7 @@ import net.minecraft.world.phys.Vec3
* @author Licious
* @since March 21st, 2022
*/
class AreaRequirement : EntityQueryRequirement {
class AreaRequirement : EntityQueryRequirement() {
companion object {
const val ADAPTER_VARIANT = "area"
}
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.pokemon.requirements
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
class AttackDefenceRatioRequirement : Requirement {
class AttackDefenceRatioRequirement : Requirement() {
companion object {
const val ADAPTER_VARIANT = "attack_defence_ratio"
}
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHit
* @since October 2nd, 2022
*/
@Suppress("unused", "CanBePrimaryConstructorProperty")
class BattleCriticalHitsRequirement(amount: Int) : Requirement {
class BattleCriticalHitsRequirement(amount: Int) : Requirement() {
constructor() : this(0)
@@ -24,7 +24,7 @@ import net.minecraft.world.level.biome.Biome
* @author Licious
* @since March 21st, 2022
*/
class BiomeRequirement : EntityQueryRequirement {
class BiomeRequirement : EntityQueryRequirement() {
val biomeCondition: RegistryLikeCondition<Biome>? = null
val biomeAnticondition: RegistryLikeCondition<Biome>? = null
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
@@ -20,7 +20,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since January 28th, 2023
*/
class BlocksTraveledRequirement(amount: Int) : Requirement {
class BlocksTraveledRequirement(amount: Int) : Requirement() {
constructor() : this(0)
@@ -22,7 +22,7 @@ import kotlin.random.Random
* @author Hiroku
* @since January 30th, 2026
*/
class ChanceRequirement : Requirement {
class ChanceRequirement : Requirement() {
companion object {
const val ADAPTER_VARIANT = "chance"
}
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionP
* @author Licious
* @since January 27th, 2022
*/
class DamageTakenRequirement(amount: Int) : Requirement {
class DamageTakenRequirement(amount: Int) : Requirement() {
constructor() : this(0)
@@ -22,7 +22,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgre
* @author Licious
* @since January 28th, 2022
*/
class DefeatRequirement(target: PokemonProperties, amount: Int) : Requirement {
class DefeatRequirement(target: PokemonProperties, amount: Int) : Requirement() {
constructor() : this(PokemonProperties(), 0)
@@ -18,7 +18,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 21st, 2022
*/
class FriendshipRequirement : Requirement {
class FriendshipRequirement : Requirement() {
val amount = 0
override fun check(pokemon: Pokemon) = pokemon.friendship >= this.amount
@@ -20,7 +20,7 @@ import net.minecraft.world.item.Items
* @author Licious
* @since March 21st, 2022
*/
class HeldItemRequirement(val itemCondition: ItemPredicate) : Requirement {
class HeldItemRequirement(val itemCondition: ItemPredicate) : Requirement() {
constructor() : this(ItemPredicate.Builder.item().of(Items.EGG).build())
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.pokemon.requirements
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
class LevelRequirement : Requirement {
class LevelRequirement : Requirement() {
companion object {
const val ADAPTER_VARIANT = "level"
}
@@ -22,7 +22,7 @@ import net.minecraft.world.entity.LivingEntity
* @author Licious
* @since January 25th, 2023
*/
class MoonPhaseRequirement(moonPhase: MoonPhase) : EntityQueryRequirement {
class MoonPhaseRequirement(moonPhase: MoonPhase) : EntityQueryRequirement() {
constructor() : this(MoonPhase.FULL_MOON)
@@ -20,7 +20,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 21st, 2022
*/
class MoveSetRequirement : Requirement {
class MoveSetRequirement : Requirement() {
val move: MoveTemplate = Moves.getByNameOrDummy("tackle")
override fun check(pokemon: Pokemon) = pokemon.moveSet.getMoves().any { move -> move.name.equals(this.move.name, true) }
companion object {
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.pokemon.Pokemon
class MoveTypeRequirement : Requirement {
class MoveTypeRequirement : Requirement() {
val type: ElementalType = ElementalTypes.NORMAL
override fun check(pokemon: Pokemon) = pokemon.moveSet.getMoves().any { move -> move.type == type }
companion object {
@@ -24,7 +24,7 @@ import net.minecraft.world.entity.player.Player
* @author Polymeta
*/
class OwnerHoldsItemRequirement(val itemCondition: ItemPredicate)
: OwnerQueryRequirement {
: OwnerQueryRequirement() {
override fun checkPlayer(
pokemon: Pokemon,
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 21st, 2022
*/
class PartyMemberRequirement : Requirement {
class PartyMemberRequirement : Requirement() {
companion object {
const val ADAPTER_VARIANT = "party_member"
}
@@ -19,7 +19,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @author Licious
* @since March 26th, 2022
*/
class PokemonPropertiesRequirement : Requirement {
class PokemonPropertiesRequirement : Requirement() {
val target = PokemonProperties()
override fun check(pokemon: Pokemon) = this.target.matches(pokemon)
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
class PropertyRangeRequirement : Requirement {
class PropertyRangeRequirement : Requirement() {
val range = IntRange(0, 256)
val feature: String = ""
@@ -21,7 +21,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgre
* @author Licious
* @since January 27th, 2022
*/
class RecoilRequirement(amount: Int) : Requirement {
class RecoilRequirement(amount: Int) : Requirement() {
constructor() : this(0)
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.pokemon.Pokemon
class StatCompareRequirement : Requirement {
class StatCompareRequirement : Requirement() {
companion object {
const val ADAPTER_VARIANT = "stat_compare"
}
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.pokemon.Pokemon
class StatEqualRequirement : Requirement {
class StatEqualRequirement : Requirement() {
companion object {
const val ADAPTER_VARIANT = "stat_equal"
}
@@ -22,7 +22,7 @@ import net.minecraft.world.level.levelgen.structure.Structure
* @author whatsy
* @since December 5th, 2023
*/
class StructureRequirement : EntityQueryRequirement {
class StructureRequirement : EntityQueryRequirement() {
val structureCondition: RegistryLikeCondition<Structure>? = null
val structureAnticondition: RegistryLikeCondition<Structure>? = null
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
@@ -20,7 +20,7 @@ import net.minecraft.world.entity.LivingEntity
* @author Licious
* @since March 26th, 2022
*/
class TimeRangeRequirement : EntityQueryRequirement {
class TimeRangeRequirement : EntityQueryRequirement() {
val range = TimeRange(0..23999)
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity) = this.range.contains((queriedEntity.level().dayTime() % DAY_DURATION).toInt())
companion object {
@@ -23,7 +23,7 @@ import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgr
* @author Licious
* @since January 25th, 2023
*/
class UseMoveRequirement(move: MoveTemplate, amount: Int) : Requirement {
class UseMoveRequirement(move: MoveTemplate, amount: Int) : Requirement() {
constructor() : this(Moves.getByNameOrDummy(""), 1)
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.api.pokemon.requirement.EntityQueryRequirement
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.world.entity.LivingEntity
class WeatherRequirement : EntityQueryRequirement {
class WeatherRequirement : EntityQueryRequirement() {
companion object {
const val ADAPTER_VARIANT = "weather"
}
@@ -21,7 +21,7 @@ import net.minecraft.world.level.Level
* @author Licious
* @since March 21st, 2022
*/
class WorldRequirement : EntityQueryRequirement {
class WorldRequirement : EntityQueryRequirement() {
companion object {
const val ADAPTER_VARIANT = "world"
}
@@ -92,7 +92,9 @@ object CobblemonPlacedFeatures {
@JvmField
val SKELETAL_FALL = of("habitats/skeletal_fall")
@JvmField
val STRANGE_FUNGAL_DWELLINGS = of("habitats/strange_fungal_dwellings")
val STRANGE_CRIMSON_FUNGAL_DWELLINGS = of("habitats/strange_crimson_fungal_dwellings")
@JvmField
val STRANGE_WARPED_FUNGAL_DWELLINGS = of("habitats/strange_warped_fungal_dwellings")
@JvmField
val VOLCANIC_PLUMES = of("habitats/volcanic_plumes")
@@ -177,7 +179,8 @@ object CobblemonPlacedFeatures {
Cobblemon.implementation.addFeatureToWorldGen(ROOT_NURSERIES, GenerationStep.Decoration.LOCAL_MODIFICATIONS, CobblemonBiomeTags.IS_SWAMP)
Cobblemon.implementation.addFeatureToWorldGen(SANDY_TIDEPOOLS, GenerationStep.Decoration.LOCAL_MODIFICATIONS, CobblemonBiomeTags.IS_BEACH)
Cobblemon.implementation.addFeatureToWorldGen(SKELETAL_FALL, GenerationStep.Decoration.LOCAL_MODIFICATIONS, CobblemonBiomeTags.IS_SOUL_SAND)
Cobblemon.implementation.addFeatureToWorldGen(STRANGE_FUNGAL_DWELLINGS, GenerationStep.Decoration.LOCAL_MODIFICATIONS, CobblemonBiomeTags.IS_WASTELAND)
Cobblemon.implementation.addFeatureToWorldGen(STRANGE_CRIMSON_FUNGAL_DWELLINGS, GenerationStep.Decoration.LOCAL_MODIFICATIONS, CobblemonBiomeTags.IS_WASTELAND)
Cobblemon.implementation.addFeatureToWorldGen(STRANGE_WARPED_FUNGAL_DWELLINGS, GenerationStep.Decoration.LOCAL_MODIFICATIONS, CobblemonBiomeTags.IS_WASTELAND)
Cobblemon.implementation.addFeatureToWorldGen(VOLCANIC_PLUMES, GenerationStep.Decoration.LOCAL_MODIFICATIONS, BiomeTags.IS_NETHER)
Cobblemon.implementation.addFeatureToWorldGen(PREHISTORIC_BIRCH_TREE, GenerationStep.Decoration.LAKES, CobblemonBiomeTags.HAS_BIRCH_LOG)
Cobblemon.implementation.addFeatureToWorldGen(PREHISTORIC_DRIPSTONE_OASIS, GenerationStep.Decoration.LAKES, CobblemonBiomeTags.IS_DRIPSTONE)
@@ -13,7 +13,10 @@ import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.BlockPos
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.LevelHeightAccessor
import net.minecraft.world.level.chunk.ChunkGenerator
import net.minecraft.world.level.levelgen.Heightmap
import net.minecraft.world.level.levelgen.RandomState
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate
@@ -24,6 +27,25 @@ class HeightRangeStructureProcessor(
val reference: HeightReference = HeightReference.SEA_LEVEL
) : StructureProcessor() {
fun isValidPlacement(world: LevelReader, pos: BlockPos): Boolean {
val referenceY = reference.getY(world, pos)
val minY = referenceY + minOffset
val maxY = referenceY + maxOffset
return pos.y in minY..maxY
}
fun isValidPlacement(
chunkGenerator: ChunkGenerator,
heightAccessor: LevelHeightAccessor,
randomState: RandomState,
pos: BlockPos
): Boolean {
val referenceY = reference.getY(chunkGenerator, heightAccessor, randomState, pos)
val minY = referenceY + minOffset
val maxY = referenceY + maxOffset
return pos.y in minY..maxY
}
override fun processBlock(
world: LevelReader,
pos: BlockPos,
@@ -32,11 +54,7 @@ class HeightRangeStructureProcessor(
currentBlockInfo: StructureTemplate.StructureBlockInfo,
data: StructurePlaceSettings
): StructureTemplate.StructureBlockInfo? {
val referenceY = reference.getY(world, pos)
val minY = referenceY + minOffset
val maxY = referenceY + maxOffset
return if (pos.y in minY..maxY) {
return if (isValidPlacement(world, pos)) {
currentBlockInfo
} else {
null
@@ -65,6 +83,19 @@ class HeightRangeStructureProcessor(
}
}
fun getY(
chunkGenerator: ChunkGenerator,
heightAccessor: LevelHeightAccessor,
randomState: RandomState,
pos: BlockPos
): Int {
return if (this == SEA_LEVEL) {
chunkGenerator.seaLevel
} else {
chunkGenerator.getBaseHeight(pos.x, pos.z, type ?: Heightmap.Types.WORLD_SURFACE_WG, heightAccessor, randomState)
}
}
companion object {
val CODEC: Codec<HeightReference> = Codec.STRING.xmap(
{ serialized -> entries.firstOrNull { it.id == serialized } ?: SEA_LEVEL },
@@ -0,0 +1,39 @@
{
"format_version": "1.8.0",
"animations": {
"animation.playrough.actor": {
"animation_length": 3,
"bones": {
"root_part": {
"position": {
"0.0": [0, 0, 0],
"0.0417": [0, 0, -3],
"0.0833": [0, 0, -6],
"0.125": [0, 0, -16],
"0.2917": [0, 0, -26],
"1.2083": [0, 0, -10],
"1.2917": [0, 0, -4],
"1.4167": [0, 0, 0]
},
"scale": {
"0.0": [1, 1, 1],
"0.0417": [1, 1, 1.05],
"0.0833": [1, 1, 1.2],
"0.125": {"pre": [0.9841, 0.9841, 1.6], "post": [0, 0, 0]},
"1.2083": {"pre": [0, 0, 0], "post": [1, 1, 1]}
}
}
},
"particle_effects": {
"0.0": {
"effect": "closecombat_actor",
"locator": "middle"
},
"0.0417": {
"effect": "closecombat_dashlines",
"locator": "middle"
}
}
}
}
}
@@ -0,0 +1,72 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:blizzard_actor",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/impact/impact_ice"
}
},
"curves": {
"variable.bsizing": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.69, 0.96, 1, 1, 1, 1, 1, 1, 0.96, 0.82, 0]
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 900,
"max_particles": 10000
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.1
},
"minecraft:emitter_shape_box": {
"offset": [0, 4, 2],
"half_dimensions": [10, 4, 10],
"direction": ["(v.particle_random_1-0.5)*0.5", "(v.target_deltay/v.target_distance)+((v.particle_random_2-0.5)*0.5)", -1]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.9,1.4)*1.1"
},
"minecraft:particle_initial_speed": "(v.particle_random_4+1)*16",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["math.sin(v.particle_age*((v.particle_random_2-0.5)*(360+(v.particle_random_2*180))))*1.5", "math.cos(v.particle_age*((v.particle_random_4-0.5)*(360+(v.particle_random_2*180))))*2", "math.sin(v.particle_age*((v.particle_random_1-0.5)*(360+(v.particle_random_2*180))))*1.5"],
"linear_drag_coefficient": 1.5
},
"minecraft:particle_appearance_billboard": {
"size": ["0.1*v.bsizing", "0.1*v.bsizing"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 56,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [0, 8],
"frames_per_second": 10,
"max_frame": 7,
"loop": true
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 0.2,
"coefficient_of_restitution": 0.05,
"collision_radius": 0.1
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFFFFF",
"1.0": "#FFAAD4FF"
}
}
}
}
}
}
@@ -0,0 +1,73 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:blizzard_target",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/impact/impact_ice"
}
},
"curves": {
"variable.dfd": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.69, 0.96, 1, 1, 1, 0.96, 0.82, 0]
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.entity_height=1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 1000,
"max_particles": 10000
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.1
},
"minecraft:emitter_shape_point": {
"direction": ["(v.particle_random_1-0.5)*3", "(v.particle_random_2-0.5)*3", "(v.particle_random_3-0.5)*3"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "0.6+(v.particle_random_4*0.4)"
},
"minecraft:particle_initial_speed": "math.random(1.25,4.75)*7",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["(v.particle_random_3-0.5)*16", "(v.particle_random_4-0.5)*16", "(v.particle_random_2-0.5)*16"],
"linear_drag_coefficient": 4
},
"minecraft:particle_appearance_billboard": {
"size": ["0.1*v.dfd", "0.1*v.dfd"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 56,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [0, 8],
"frames_per_second": 10,
"max_frame": 7,
"stretch_to_lifetime": true
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 0.2,
"coefficient_of_restitution": 0.6,
"collision_radius": 0.1
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFFFFF",
"1.0": "#FFAAD4FF"
}
}
}
}
}
}
@@ -0,0 +1,64 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:blizzard_targetswirl",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/impact/impact_ice"
}
},
"curves": {
"variable.dfd": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.69, 0.96, 1, 1, 1, 0.96, 0.82, 0]
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.entity_height=1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 200,
"max_particles": 10000
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.7
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "0.6+(v.particle_random_4*0.4)"
},
"minecraft:particle_motion_parametric": {
"relative_position": ["(math.sin((v.particle_age*420)+(v.particle_random_1*360))*(math.clamp(v.entity_radius*1.04,0.65,4)+(v.particle_age*1.7)))", "(math.cos((v.particle_age*410)+(v.particle_random_1*360))*0.25)+((((v.particle_random_2-0.5)*2)*(v.entity_height*0.65))+((v.particle_age+v.particle_age)*(v.particle_random_4-0.5)))", "(math.cos((v.particle_age*410)+(v.particle_random_1*360))*(math.clamp(v.entity_radius*1.04,0.65,4)+(v.particle_age*1.7)))"]
},
"minecraft:particle_appearance_billboard": {
"size": ["0.1*v.dfd", "0.1*v.dfd"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 56,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [0, 8],
"frames_per_second": 10,
"max_frame": 7,
"loop": true
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFFFFF",
"1.0": "#FFAAD4FF"
}
}
}
}
}
}
@@ -37,7 +37,7 @@
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": ["0.35+(v.particle_age*0.175)", "0.35+(v.particle_age*0.175)"],
"facing_camera_mode": "rotate_xyz",
"facing_camera_mode": "emitter_transform_xy",
"uv": {
"texture_width": 117,
"texture_height": 13,
@@ -48,7 +48,7 @@
0.55,
0.55
],
"facing_camera_mode": "rotate_xyz",
"facing_camera_mode": "emitter_transform_xy",
"uv": {
"texture_width": 68,
"texture_height": 17,
@@ -0,0 +1,60 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:disarmingvoice_actor1",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/ring/largering"
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.target_deltaz=5;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 8,
"max_particles": 7
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.1
},
"minecraft:emitter_shape_point": {
"offset": ["v.target_deltax*(v.emitter_age/v.emitter_lifetime)", "v.target_deltay*(v.emitter_age/v.emitter_lifetime)", "-(v.target_deltaz*(v.emitter_age/v.emitter_lifetime))"],
"direction": [0, "(v.target_deltay/v.target_distance)", -1]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.43
},
"minecraft:particle_initial_speed": "math.clamp(v.target_deltaz,1,12)",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": "math.clamp(v.target_deltaz*1.5,3,10)"
},
"minecraft:particle_appearance_billboard": {
"size": [0.75, 0.75],
"facing_camera_mode": "emitter_transform_xy",
"uv": {
"texture_width": 160,
"texture_height": 20,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [20, 20],
"step_UV": [20, 0],
"frames_per_second": 20,
"max_frame": 8
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFECFE",
"0.47": "#FFFF89E8",
"1.0": "#FFE600BA"
}
}
}
}
}
}
@@ -0,0 +1,60 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:disarmingvoice_actor2",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/ring/mediumring"
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.target_deltaz=5;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 8,
"max_particles": 7
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.1
},
"minecraft:emitter_shape_point": {
"offset": ["v.target_deltax*(v.emitter_age/v.emitter_lifetime)", "v.target_deltay*(v.emitter_age/v.emitter_lifetime)", "-(v.target_deltaz*(v.emitter_age/v.emitter_lifetime))"],
"direction": [0, "(v.target_deltay/v.target_distance)", -1]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.3
},
"minecraft:particle_initial_speed": "math.clamp(v.target_deltaz,1,12)",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": "math.clamp(v.target_deltaz*1.5,3,10)"
},
"minecraft:particle_appearance_billboard": {
"size": [0.55, 0.55],
"facing_camera_mode": "emitter_transform_xy",
"uv": {
"texture_width": 90,
"texture_height": 15,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [15, 15],
"step_UV": [15, 0],
"frames_per_second": 20,
"max_frame": 6
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFECFE",
"0.47": "#FFFF89E8",
"1.0": "#FFE600BA"
}
}
}
}
}
}
@@ -0,0 +1,63 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:disarmingvoice_actorhearts",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/status/infatuation_heart"
}
},
"curves": {
"variable.d": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.93, 1, 1, 1, 0.93, 0.61, 0]
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.target_deltaz=5;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 25,
"max_particles": 2000
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.1
},
"minecraft:emitter_shape_point": {
"offset": ["(v.target_deltax*(v.emitter_age/v.emitter_lifetime))+math.sin(v.emitter_age*360*7.5)*0.7", "(v.target_deltay*(v.emitter_age/v.emitter_lifetime))+math.cos(v.emitter_age*360*7.5)*0.7", "-(v.target_deltaz*(v.emitter_age/v.emitter_lifetime))"],
"direction": [0, "(v.target_deltay/v.target_distance)", -1]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.45
},
"minecraft:particle_initial_speed": "v.target_deltaz*0.5",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["(v.particle_random_1-0.5)", "(v.particle_random_2-0.5)", "(v.particle_random_3-0.5)"],
"linear_drag_coefficient": 4
},
"minecraft:particle_appearance_billboard": {
"size": ["(0.1-(v.particle_random_4*0.04))*v.d", "(0.1-(v.particle_random_4*0.04))*v.d"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 90,
"texture_height": 9,
"uv": [3, 3],
"uv_size": [3, 3]
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFF89E8",
"1.0": "#FFE600BA"
}
}
}
}
}
}
@@ -0,0 +1,70 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:disarmingvoice_target",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/ring/xlring"
}
},
"curves": {
"variable.s": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0.24, 0.69, 0.9, 0.98, 1, 1, 1, 1, 1, 1, 1, 1, 1]
}
},
"events": {
"event": {
"particle_effect": {
"effect": "cobblemon:disarmingvoice_targetsparks",
"type": "emitter"
}
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.1
},
"minecraft:emitter_lifetime_events": {
"creation_event": "event"
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.43
},
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": ["1*v.s", "1*v.s"],
"facing_camera_mode": "emitter_transform_xy",
"uv": {
"texture_width": 160,
"texture_height": 20,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [20, 20],
"step_UV": [20, 0],
"frames_per_second": 20,
"max_frame": 8
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFECFE",
"0.47": "#FFFF89E8",
"1.0": "#FFE600BA"
}
}
}
}
}
}
@@ -0,0 +1,64 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:disarmingvoice_targetsparks",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/orb/scaling"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 1, 0.98, 0.86, 0.6, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 10
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_point": {
"direction": ["math.random(-0.91,0.91)", "math.random(-0.81, 1.01)", "math.random(-0.91,0.91)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.45, 0.6)"
},
"minecraft:particle_initial_speed": "(0.8+(v.particle_random_4*0.6))*10",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["(v.particle_random_1-0.5)*7", "(v.particle_random_2-0.5)*7", "(v.particle_random_3-0.5)*7"],
"linear_drag_coefficient": 5
},
"minecraft:particle_appearance_billboard": {
"size": ["0.11*v.size", "0.11*v.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 32,
"flipbook": {
"base_UV": [0, 16],
"size_UV": [8, 8],
"step_UV": [0, -8],
"frames_per_second": 12,
"max_frame": 3,
"stretch_to_lifetime": true
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFECFE",
"0.93": "#FFE600BA"
}
}
}
}
}
}
@@ -0,0 +1,77 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:dragonbreath_actor",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/fire/cloudyfire_white"
}
},
"curves": {
"variable.fun": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 1, 1, 1, 0.99, 0.97, 0.91, 0.77, 0.54, -0.1]
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.target_deltaz=5;v.target_deltax=0;v.target_deltay=0;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": "30*(math.clamp(v.target_deltaz,1,4))",
"max_particles": 1000
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_point": {
"direction": ["(-v.target_deltax+((v.particle_random_1-0.5)*1.05))+(math.sin(v.emitter_age*360)*0.25)", "(v.target_deltay+((v.particle_random_2-0.5)*1.05))+(math.sin(v.emitter_age*540)*0.2)", "-v.target_deltaz*1.05"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.75,1.0)*1.4"
},
"minecraft:particle_initial_spin": {
"rotation": "math.round(v.particle_random_4*3)*90"
},
"minecraft:particle_initial_speed": "(v.target_deltaz*((v.particle_random_4+0.75)*1.15))*(math.clamp(v.target_deltaz,3,24)/1.7)",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["(v.particle_random_3-0.5)*4", "3+(v.particle_random_1-0.5)*2", "(v.particle_random_2-0.5)*1"],
"linear_drag_coefficient": "math.clamp(v.target_deltaz,1,20)*(0.5+(math.clamp(v.target_deltaz,1,5)*0.05))"
},
"minecraft:particle_appearance_billboard": {
"size": ["(0.5-(v.particle_random_4*0.15))*v.fun", "(0.5-(v.particle_random_4*0.15))*v.fun"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 160,
"texture_height": 16,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [16, 16],
"step_UV": [16, 0],
"frames_per_second": 12,
"max_frame": 10
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 10,
"collision_radius": 0.01
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "(v.particle_age / v.particle_lifetime) * (v.particle_random_4+0.75)",
"gradient": {
"0.0": "#FFFFE6A1",
"0.05": "#FFFFE6A1",
"0.2": "#FFFF3B8F",
"0.6": "#FFA300FF",
"1.0": "#FF3E00C7"
}
}
}
}
}
}
@@ -0,0 +1,71 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:dragonbreath_target",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/fire/cloudyfire_white"
}
},
"curves": {
"variable.dorasize": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0.42, 0.77, 0.91, 0.98, 1, 1, 1, 1, 1, 0.86, 0.55, 0]
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 250,
"max_particles": 150
},
"minecraft:emitter_lifetime_looping": {
"active_time": 0.3
},
"minecraft:emitter_shape_point": {
"offset": [0, 0, "math.random(0.15,-0.05)"],
"direction": ["math.random(-2,2)*1.1", "math.random(-2,2)*1.1", "math.random(-2,2)*0.45"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.65,1.0)*1.4"
},
"minecraft:particle_initial_speed": "math.random(1.25,4.75)*1.25",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, "math.random(1.5,3.5)", 0],
"linear_drag_coefficient": "math.random(1.25,1.5)*2"
},
"minecraft:particle_appearance_billboard": {
"size": ["(0.5-(v.particle_random_4*0.15))*v.dorasize", "(0.5-(v.particle_random_4*0.15))*v.dorasize"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 160,
"texture_height": 16,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [16, 16],
"step_UV": [16, 0],
"frames_per_second": 12,
"max_frame": 10
}
}
},
"minecraft:particle_motion_collision": {
"coefficient_of_restitution": 0.1,
"collision_radius": 0.1
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFE6A1",
"0.35": "#FFFF3B8F",
"0.7": "#FFA300FF",
"1.0": "#FF3E00C7"
}
}
}
}
}
}
@@ -0,0 +1,74 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:dragonrage_actor",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/fire/cloudyfire_white"
}
},
"curves": {
"variable.fun": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 1, 1, 0.99, 0.95, 0.8, 0.5, 0.05]
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.target_deltaz=5;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 60,
"max_particles": 300
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.65
},
"minecraft:emitter_shape_point": {
"offset": ["-v.target_deltax*(v.emitter_age/v.emitter_lifetime)", "v.target_deltay*(v.emitter_age/v.emitter_lifetime)", "-v.target_deltaz*(v.emitter_age/v.emitter_lifetime)"],
"direction": ["math.random(-0.45,0.45)", "math.random(-0.45,0.45)-(v.target_deltay/v.target_deltaz)", "math.random(-2.05,-0.55)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.7
},
"minecraft:particle_initial_spin": {
"rotation": "math.round(v.particle_random_4*3)*90"
},
"minecraft:particle_initial_speed": "math.random(2.75,3.25)*(v.target_deltaz*0.5)",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["(v.particle_random_1-0.5)*4", "1.5+(v.particle_random_1-0.5)*3", "(v.particle_random_1-0.5)*3"],
"linear_drag_coefficient": 4
},
"minecraft:particle_appearance_billboard": {
"size": ["0.45*v.fun", "0.45*v.fun"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 160,
"texture_height": 16,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [16, 16],
"step_UV": [16, 0],
"frames_per_second": 20,
"max_frame": 10
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFA1A1",
"0.05": "#FFFFA1A1",
"0.2": "#FFFF3BF2",
"0.6": "#FF7C00FF",
"1.0": "#FF3E00C7"
}
}
}
}
}
}
@@ -0,0 +1,85 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:dragonrage_actorburst",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/generic/fire/cloudyfire_white"
}
},
"curves": {
"variable.fun": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 1, 1, 1, 0.97, 0.87, 0.54, 0]
}
},
"events": {
"ring": {
"particle_effect": {
"effect": "cobblemon:dragonrage_actorring",
"type": "emitter"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 200,
"max_particles": 1000
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.1
},
"minecraft:emitter_lifetime_events": {
"creation_event": "ring"
},
"minecraft:emitter_shape_point": {
"direction": ["math.random(-1.05,1.05)*1.25", "math.random(-1.05,1.05)*1.25", "math.random(-1.25,-0.05)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.4,0.8)"
},
"minecraft:particle_initial_spin": {
"rotation": "math.round(v.particle_random_4*3)*90"
},
"minecraft:particle_initial_speed": "math.random(2.5,7.5)*2",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["(v.particle_random_1-0.5)*4", "3+(v.particle_random_1-0.5)*3", "(v.particle_random_1-0.5)*1"],
"linear_drag_coefficient": 4
},
"minecraft:particle_appearance_billboard": {
"size": ["(0.5-(v.particle_random_4*0.15))*v.fun", "(0.5-(v.particle_random_4*0.15))*v.fun"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 160,
"texture_height": 16,
"flipbook": {
"base_UV": [16, 0],
"size_UV": [16, 16],
"step_UV": [16, 0],
"frames_per_second": 20,
"max_frame": 9
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 10,
"collision_radius": 0.01
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFA1A1",
"0.05": "#FFFFA1A1",
"0.2": "#FFFF3BF2",
"0.6": "#FF7C00FF",
"1.0": "#FF3E00C7"
}
}
}
}
}
}
@@ -0,0 +1,63 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:dragonrage_actorring",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/generic/ring/xlring"
}
},
"curves": {
"variable.s": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.57, 0.84, 0.96, 1, 1, 1, 1, 1, 1, 1]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.05
},
"minecraft:emitter_shape_point": {
"offset": [0, 0, -0.1]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.45
},
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": ["1.2*v.s", "1.2*v.s"],
"facing_camera_mode": "emitter_transform_xy",
"uv": {
"texture_width": 200,
"texture_height": 25,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [25, 25],
"step_UV": [25, 0],
"frames_per_second": 20,
"max_frame": 8
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFA1A1",
"0.05": "#FFFFA1A1",
"0.2": "#FFFF3BF2",
"0.78": "#FF6600C7",
"1.0": "#003E00C7"
}
}
}
}
}
}

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