Compare commits

...
Author SHA1 Message Date
Slippy 8e3724a623 Lush Cove Adjustments 2024-12-22 11:48:44 -06:00
Slippy 4940afbd81 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into Cove-Adjustments 2024-12-22 11:31:58 -06:00
Hiroku d29e471ab4 Merge branch 'ok-fine-heres-a-journey-molang-mr' into 'main'
[1.6 pls] Journey Molang Migration

See merge request cable-mc/cobblemon!1385
2024-12-22 08:10:23 +00:00
Paul 6c1e6677b3 More molang cleanup 2024-12-22 18:03:31 +10:00
Paul aaa7fcee47 Cleaned up particle molang functions, moved reusable particle spawning logic from netcode to ParticleStorm 2024-12-22 18:01:05 +10:00
Hiroku 37b050f2e5 Merge branch 'ihatebugtypes' into 'main'
Ihatebugtypes

Closes #1167, #1201, and #1225

See merge request cable-mc/cobblemon!1369
2024-12-22 06:24:19 +00:00
Hiroku 16ccd6bcc3 Merge branch 'upstream/npcs' into 'main'
Allow for programmatic persistence of npcs

See merge request cable-mc/cobblemon!1388
2024-12-22 06:23:00 +00:00
Paul 8b0d228339 Merge remote-tracking branch 'origin/main' 2024-12-22 12:07:59 +10:00
Paul 5019026472 Further reworked brewing, JEI/EMI compat might exist on Neo now (fabric is impossibru (for now)) 2024-12-22 12:07:48 +10:00
amo ace38ad6be Merge branch 'main' into ok-fine-heres-a-journey-molang-mr 2024-12-21 17:03:47 +00:00
Polymeta 5c885112ef Merge branch '1.6-additional-additions' into 'main'
1.6 additional additions

See merge request cable-mc/cobblemon!1398
2024-12-21 14:23:06 +00:00
Plastered_Crab a37532579e 1.6 additional additions 2024-12-21 14:23:05 +00:00
Segfault Guy 0f751eb732 cleanup 2024-12-21 07:18:41 -05:00
Paul 9840a2758a Fixed everything being medicinal brew. Drink it!!! (fixes #1249) 2024-12-21 22:07:30 +10:00
Paul ad52d1ed5f Fixed busted flowers tag, fixed party check criterion 2024-12-21 21:48:09 +10:00
Paul 74464dc13a Fixed PC block waterlog property not being the right one, causing export issues, closes #1253 2024-12-21 21:33:24 +10:00
Hiroku f280ec8979 Merge branch 'half-slabs' into 'main'
Stonecutter Fixes

Closes #1260

See merge request cable-mc/cobblemon!1399
2024-12-21 05:57:42 +00:00
dhi_holo 25ca0fbd13 Recreate flowers.json
Moved the working flowers.json from being just in items to being a block tag too
2024-12-21 15:25:33 +10:00
dhi_holo 2c8d544088 Tag Fix
Cleans up a tag, removes a recursive tag error, and tweaks a spawn to be valid again.
2024-12-21 15:16:12 +10:00
Segfault Guy 7dbe31d084 Merge remote-tracking branch 'origin/main' into ihatebugtypes 2024-12-20 23:47:30 -05:00
Segfault Guy de05133b31 update licenses 2024-12-20 23:45:45 -05:00
Segfault Guy 3b70b8351a Block battles on evolution. 2024-12-20 23:44:36 -05:00
dhi_holo 784439475a Stonecutter Fixes
Moved the count value from outside the result to inside of it. No idea why it ended up outside, but hey, easy fix. Resolves #1260
2024-12-21 14:22:44 +10:00
Paul 2024ddb4f0 Wrap spawn direction angle within acceptable entity rotation values 2024-12-21 12:37:32 +10:00
Paul ad35be7ddb Added player level range influence to fishing 2024-12-21 10:51:27 +10:00
Paul dbf688fade Merge remote-tracking branch 'origin/lang-updates'
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/de_de.json
#	common/src/main/resources/assets/cobblemon/lang/es_mx.json
#	common/src/main/resources/assets/cobblemon/lang/th_th.json
2024-12-21 09:30:37 +10:00
Polymeta 17d3d5f829 Merge branch 'implement_pokemon' into 'main'
This weeks pokemon implementation

Closes #1230 and #1137

See merge request cable-mc/cobblemon!1397
2024-12-20 13:30:37 +00:00
Frank The Farmer fba00c23b4 This weeks pokemon implementation 2024-12-20 13:30:35 +00:00
Hiroku cfe516e086 Merge branch 'RaftClientSyncFix' into 'main'
Fixed client sync issue with platforms. (Clients do not possess accurate behavior data.)

See merge request cable-mc/cobblemon!1394
2024-12-20 10:29:40 +00:00
Polymeta 63d921cb12 Merge branch 'fix-drop-message' into 'main'
Fix 'air dropped to the ground' message when Pokémon are killed in lava and drop no loot

See merge request cable-mc/cobblemon!1395
2024-12-20 09:23:07 +00:00
lion 6acde8c90f Fix 'air dropped to the ground' message when Pokémon are killed in lava and drop no loot 2024-12-20 09:23:07 +00:00
Hiroku 196ce2ab6d Merge branch 'fix-evolution-animation' into 'main'
Fix evolution animation not playing back to back

Closes #1229

See merge request cable-mc/cobblemon!1396
2024-12-20 09:09:12 +00:00
lion 6fb6ea2927 Fix evolution animation not playing back to back 2024-12-20 09:09:12 +00:00
JazzMcNade 538027cb1b Fixed client sync issue with platforms. (Clients do not possess accurate behavior data.) 2024-12-19 17:47:17 -06:00
Paul 51fcc91d88 Fixed blinks not running 2024-12-19 21:24:00 +10:00
Gustavo Felippi Puerari 63c603cc01 Translated using Weblate (Portuguese (Brazil))
Currently translated at 33.9% (2169 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2024-12-18 23:02:36 +00:00
Teggy a7406dd321 Translated using Weblate (Spanish)
Currently translated at 98.0% (6267 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2024-12-18 23:02:36 +00:00
Paul 0e1611fd8e Merge remote-tracking branch 'origin/main' 2024-12-18 19:15:35 +10:00
Paul 51e575c6a6 Fixed action effects not playing animations, particles, or sounds in many circumstances. Tweaked spawn direction handling 2024-12-18 19:15:17 +10:00
Test 8789d16a53 replace hardcoded values with attribute for item interaction range 2024-12-17 22:09:12 -05:00
Gustavo Felippi Puerari f7986d5ccf Translated using Weblate (Portuguese (Brazil))
Currently translated at 33.7% (2160 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2024-12-18 02:41:45 +00:00
Felipe Bermudes Ormeño c7423408a9 Translated using Weblate (Spanish (Mexico))
Currently translated at 30.6% (1960 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es_MX/
2024-12-18 02:41:44 +00:00
Teggy 52b0c63751 Translated using Weblate (Spanish)
Currently translated at 96.8% (6189 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2024-12-18 02:41:44 +00:00
Polymeta 7ae20ccd60 Merge branch 'scrappy-lang-fix' into 'main'
Updated Scrappy's ability description

See merge request cable-mc/cobblemon!1389
2024-12-17 23:53:29 +00:00
Conan 621b867d14 Updated Scrappy's ability description 2024-12-17 21:46:24 +01:00
chasem-dev b0ea22d220 Allow for programmatic persistence of npcs 2024-12-17 15:19:56 -05:00
amo dfb54b3bc3 brainfart 2024-12-17 01:17:01 +00:00
Polymeta 2928667500 Merge branch '1.6-spawns' into 'main'
Updated recipes for Scope Lens, Wide Lens, and Zoom Lens. Updated spawns....

See merge request cable-mc/cobblemon!1384
2024-12-16 23:50:04 +00:00
Veraxiel 1c528a909c Updated recipes for Scope Lens, Wide Lens, and Zoom Lens. Updated spawns.... 2024-12-16 23:50:04 +00:00
amo 1083e770d0 add player-specific packet molang methods for snowstorm particles & animations 2024-12-16 12:43:15 +00:00
Paul 920f3f114b Merge remote-tracking branch 'origin/main' 2024-12-16 21:08:27 +10:00
Hiroku 9ca5d12f84 Merge branch 'FixInBattleFlightFidgeting' into 'main'
FixInBattleFlightFidgeting

See merge request cable-mc/cobblemon!1383
2024-12-16 09:41:22 +00:00
Hiroku cc9bb528a8 Merge branch 'npc-hitbox' into 'main'
Fixed npcs not being able to take custom hitbox properties

See merge request cable-mc/cobblemon!1381
2024-12-16 09:40:46 +00:00
Paul 1cbd00691f Merge remote-tracking branch 'origin/main' 2024-12-16 19:05:10 +10:00
JazzMcNade f4c847fdd5 Replaced isGrounded with the more reliable isAirborne. Prevented pokemon from currently flying from receiving a raft. 2024-12-16 01:04:46 -06:00
Conan ec6e1403e7 Fixed npcs not being able to take custom hitbox properties 2024-12-16 05:24:26 +01:00
Hiroku 10a4a03a8b Merge branch 'close-battle-gui-with-mouse' into 'main'
Fix battle GUI not closing with mouse keybind

Closes #1093

See merge request cable-mc/cobblemon!1380
2024-12-16 03:06:46 +00:00
lion e0a86f8794 Fix battle GUI not closing with mouse keybind 2024-12-16 03:06:45 +00:00
Paul 767e024ec4 Debug logging of pokemon entity ticking 2024-12-16 09:55:45 +10:00
Polymeta c8b0f36049 Merge branch 'bugfixes-apion' into 'main'
Fixes #1182

Closes #1182

See merge request cable-mc/cobblemon!1373
2024-12-15 18:25:02 +00:00
Apion be2a0be806 Fixes #1182 2024-12-15 18:25:02 +00:00
Paul ba4d42ccf6 Try tweaking spawn direction handling 2024-12-15 23:04:08 +10:00
Paul 5545d3498f Include 2 more variables in clamping of rotations 2024-12-15 20:53:50 +10:00
Hiroku 641bd7ebaa Merge branch 'advancing' into 'main'
1.6 Advancement Reworks

See merge request cable-mc/cobblemon!1374
2024-12-15 09:16:28 +00:00
dhi_holo 234c4fa0d4 1.6 Advancement Reworks 2024-12-15 09:16:28 +00:00
Hiroku 3dfda71ed5 Merge branch 'AbilityPatchCapsuleRefactor' into 'main'
AbilityPatchCapsuleRefactor

See merge request cable-mc/cobblemon!1377
2024-12-15 09:08:05 +00:00
Hiroku 65ee6de93f Merge branch 'chest-boat-interact' into 'main'
moved changes to chest boat (i'm dumb)

Closes #1214

See merge request cable-mc/cobblemon!1379
2024-12-15 09:07:48 +00:00
Paul be88b727bc Added useFixedRandom to pool party provider, added randomizePartyOrder to NPC classes and presets for randomly choosing lead battle pokemon 2024-12-15 18:04:04 +10:00
luke a69fc462ee moved changes to chest boat (i'm dumb) 2024-12-15 00:38:08 -07:00
Hiroku 7d5c30d27c Merge branch 'shift-click-interact' into 'main'
Changed distance to use player attribute

Closes #1232

See merge request cable-mc/cobblemon!1378
2024-12-15 07:32:39 +00:00
Hiroku f7c9c9d4f4 Update AbilityTypeChanger.kt 2024-12-15 07:30:12 +00:00
luke 41bc14168a Changed distance to use player attribute 2024-12-15 00:24:38 -07:00
Paul 9540c38a72 Updated readme example for NPC 2024-12-15 16:58:31 +10:00
JazzMcNade 7a96ed7cd1 Refactored queryPossible() as to not to require explicit Priority values 2024-12-15 00:45:51 -06:00
Hiroku 677adc8d2f Merge branch 'starter-selection-cry' into 'main'
Play cry when Pokémon is clicked on the starter selection screen

See merge request cable-mc/cobblemon!1362
2024-12-15 06:25:29 +00:00
lion a99b1dfc6c Play cry when Pokémon is clicked on the starter selection screen 2024-12-15 06:25:29 +00:00
Hiroku 4a718ad0f6 Merge branch 'dex-update-event' into 'main'
Dex Data Updated Event

See merge request cable-mc/cobblemon!1353
2024-12-15 05:27:08 +00:00
Paul ddd417d458 Added player to PokedexDataChangedEvent's flow context 2024-12-15 15:19:43 +10:00
Paul 10a12a897e Merge remote-tracking branch 'origin/main' into dex-update-event 2024-12-15 15:15:48 +10:00
Paul 9fce99ed73 Improved dex event, added dex update flow, expanded dex molang and added q.player.pokedex 2024-12-15 15:15:13 +10:00
Hiroku c35f60dd5d Merge branch 'AbilitiesFixesRedux' into 'main'
AbilitiesFixesRedux

Closes #1245

See merge request cable-mc/cobblemon!1376
2024-12-15 03:11:07 +00:00
JazzMcNade 54e5a5e819 Fixed single abilities mons always evolving into the hidden ability. Fixed ability capsule / patch not being able to revert abilities. 2024-12-14 20:35:23 -06:00
Test 79ae35ea9e Merge branch 'n-p-c' into 'main'
fix npc scaling + eye height, update edit interface

See merge request cable-mc/cobblemon!1375
2024-12-15 02:17:45 +00:00
Test 58f85e6d0d fix npc scaling + eye height, update edit interface 2024-12-15 02:17:45 +00:00
Polymeta 71bfdf41f4 Merge branch 'the-else-strikes-back' into 'main'
Fix Feebas spawning

Closes #1187

See merge request cable-mc/cobblemon!1365
2024-12-15 01:13:26 +00:00
Jordan 9976965673 Fix Feebas spawning 2024-12-15 01:13:26 +00:00
Hiroku 098df1a5a6 Merge branch 'dex-travelling-dimensions' into 'main'
Fix Pokédex screen getting stuck when changing dimensions or opening the battle GUI

See merge request cable-mc/cobblemon!1370
2024-12-15 01:09:47 +00:00
Guilherme Pereira f49f34efa3 Fix Pokédex screen getting stuck when changing dimensions or opening the battle GUI 2024-12-15 01:09:47 +00:00
Hiroku eac19929c4 Merge branch 'fix-dex-animations-not-playing' into 'main'
Fix animations not playing on Pokédex

See merge request cable-mc/cobblemon!1355
2024-12-15 00:43:09 +00:00
Guilherme Pereira 59cced5b2c Fix animations not playing on Pokédex 2024-12-15 00:43:08 +00:00
Apion f07707221f Merge branch 'implement_pokemon' into 'main'
Pokémon fixes and tweaks

Closes #1230 and #1137

See merge request cable-mc/cobblemon!1371
2024-12-14 23:57:34 +00:00
Polymeta 89b89592ab Pokémon fixes and tweaks 2024-12-14 23:57:33 +00:00
Hiroku cdeb977769 Update DexInformationChangedEvent.kt 2024-12-14 23:55:43 +00:00
Gustavo Felippi Puerari 78192c43a7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 33.6% (2148 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2024-12-14 18:41:41 +00:00
Paul a3987b433c Merge remote-tracking branch 'origin/main' 2024-12-14 22:19:51 +10:00
Paul 99de91bd7e Added optional level property to pool party providers for using molang to force a level value, closes #1244 2024-12-14 22:19:39 +10:00
Paul 4b292b1241 Less zealous on the warning logging 2024-12-14 22:16:07 +10:00
Hiroku 1e6e4d8c5f Merge branch 'moe-eats-bugs' into 'main'
Added ignore checks to prevent passive healing/revival when config values are 0

Closes #875

See merge request cable-mc/cobblemon!1372
2024-12-14 11:41:35 +00:00
MoeBoy76 9a61c3471b Added ignore checks to prevent passive healing/revival when config values are 0 2024-12-14 22:12:08 +11:00
Paul 77f7439853 Fixed brewing on neoforged 2024-12-14 14:51:01 +10:00
Segfault Guy 439161c180 Merge remote-tracking branch 'origin/main' into ihatebugtypes 2024-12-13 23:39:22 -05:00
Paul e9718b7e8b Merge remote-tracking branch 'origin/main' 2024-12-14 14:29:28 +10:00
Hiroku 4cadd4e20f Merge branch 'fix/watchdog' into 'main'
Watchdog: Possible fix for watchdog crashing

See merge request cable-mc/cobblemon!1368
2024-12-14 04:26:24 +00:00
Hiroku 17a3d86324 Update PokemonEntity.kt 2024-12-14 04:25:19 +00:00
Hiroku 48653073f5 if ( 2024-12-14 04:21:49 +00:00
Nick 82c7c03e28 Initial tests for watchdog fix 2024-12-13 20:18:13 -08:00
Nick 2d7f3257d1 Merge branch 'hiro-fix' into 'main'
I fix bugs too

Closes #1212, #1222, and #1228

See merge request cable-mc/cobblemon!1367
2024-12-14 04:16:35 +00:00
Hiroku bc7b4f94c2 I fix bugs too 2024-12-14 04:16:35 +00:00
Paul 7a9e9d7ced Fixed battles being startable while pokemon are busy, closes #1212 2024-12-14 13:52:19 +10:00
Paul 0f85ece16f Fixed cry sound effects playing twice for specific cases, closes #1222 2024-12-14 13:36:53 +10:00
Paul c4656e1a4e Fixed cubone alola bias not being visible, closes #1228 2024-12-14 12:57:17 +10:00
Paul 0c48a318c5 Added /runmolangscript, updated molang version 2024-12-14 12:22:25 +10:00
Paul dab89a9f8c Merge remote-tracking branch 'origin/main' 2024-12-14 11:05:55 +10:00
Paul 53fd2dba2d Fixed flows double-registering then triple-registering then quadruple-registering then- 2024-12-14 11:05:48 +10:00
Polymeta a5b15c6127 Merge branch 'more-items-tooltips' into 'main'
Add tooltips to many items

See merge request cable-mc/cobblemon!1346
2024-12-14 00:48:11 +00:00
Guilherme Pereira 174fb59bbb Add tooltips to many items 2024-12-14 00:48:11 +00:00
Paul 2f8bd44938 Added q.set_query for assigning new query function values, closes #1240 2024-12-14 10:36:53 +10:00
Paul 9d58c7126e Fixed set_npc_variable not initializing NPC data properly 2024-12-14 10:12:50 +10:00
Hiroku 2afd722125 Incl default return for get_npc_variable when no data exists for the NPC yet 2024-12-14 00:03:25 +00:00
Polymeta c9cfe489d6 Merge branch 'EV-Berry-Lang-fixes' into 'main'
Fixed lang files for EV lowering berries to actually be correct

See merge request cable-mc/cobblemon!1364
2024-12-13 11:23:29 +00:00
Plastered_Crab 4ee029fa54 Fixed lang files for EV lowering berries to actually be correct 2024-12-12 09:41:17 -08:00
Teggy e2ebb32708 Translated using Weblate (Spanish)
Currently translated at 87.6% (5601 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2024-12-11 15:53:06 +00:00
Segfault Guy b0466447cc Temp fix for missing form langs. 2024-12-10 21:59:39 -05:00
Zack the Ghast 727ff96ff8 Translated using Weblate (Portuguese (Portugal))
Currently translated at 28.9% (1851 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2024-12-10 12:41:43 +00:00
Gustavo Felippi Puerari 9307f957b7 Translated using Weblate (Portuguese (Brazil))
Currently translated at 32.6% (2089 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2024-12-10 12:41:43 +00:00
Teggy d48978f6a4 Translated using Weblate (Spanish)
Currently translated at 86.5% (5531 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2024-12-10 12:41:42 +00:00
amo d1a8171079 resolve threads 2024-12-09 23:57:38 +00:00
amo d4b673ea38 Merge branch 'main' into dex-update-event 2024-12-09 23:54:08 +00:00
amo de21b7c402 forgot me loighter 2024-12-07 04:44:27 +00:00
amo 10fe3c4362 🍋‍🟩 Chore: Add Dex data update event 2024-12-07 04:40:50 +00:00
Gustavo Felippi Puerari aca1433595 Translated using Weblate (Portuguese (Brazil))
Currently translated at 30.8% (1969 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2024-12-07 03:41:43 +00:00
Teggy 082c382179 Translated using Weblate (Spanish)
Currently translated at 80.4% (5140 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es/
2024-12-07 03:41:42 +00:00
Segfault Guy c2d85a0cdf Battle performance, bugs, and PokemonEntity fixes. 2024-12-05 00:22:20 -05:00
Weblate 7cea5ad69e Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/
2024-12-04 00:41:50 +00:00
Zack the Ghast 0b9b5ac306 Translated using Weblate (Portuguese (Portugal))
Currently translated at 28.8% (1845 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2024-12-04 00:41:46 +00:00
Gustavo Felippi Puerari 8941f3079b Translated using Weblate (Portuguese (Brazil))
Currently translated at 29.1% (1866 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2024-12-04 00:41:44 +00:00
Alexis Salgueiro e9a0815ca6 Translated using Weblate (French)
Currently translated at 100.0% (6391 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-12-04 00:41:41 +00:00
Plastered_Crab db25ebf7f1 Add placeholder type gem blocks (regular and budding) for testing 2024-12-03 13:41:57 -08:00
Zack the Ghast fe48da6277 Translated using Weblate (Portuguese (Portugal))
Currently translated at 27.3% (1750 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2024-11-29 09:15:34 +00:00
Mia 12c9c1c295 Translated using Weblate (German)
Currently translated at 88.8% (5679 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2024-11-29 09:15:33 +00:00
Zack the Ghast 7471b336be Translated using Weblate (Portuguese (Portugal))
Currently translated at 26.9% (1720 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_PT/
2024-11-26 12:15:28 +00:00
Natchakot Chuchokjatuporn 948f299f8f Translated using Weblate (Thai)
Currently translated at 90.1% (5764 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/th/
2024-11-18 21:41:42 +00:00
Natchakot Chuchokjatuporn 5c075d7d29 Translated using Weblate (Thai)
Currently translated at 88.7% (5671 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/th/
2024-11-13 22:41:55 +00:00
Weblate 854f02d34f Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/
2024-11-12 21:41:59 +00:00
Natchakot Chuchokjatuporn a3c3fa12e5 Translated using Weblate (Thai)
Currently translated at 87.1% (5567 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/th/
2024-11-12 21:41:53 +00:00
Alexis Salgueiro 3527da02a6 Translated using Weblate (French)
Currently translated at 100.0% (6391 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-12 21:41:48 +00:00
Mia 96f537fa27 Translated using Weblate (German)
Currently translated at 87.5% (5596 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2024-11-12 21:41:45 +00:00
Natchakot Chuchokjatuporn e9f58df359 Translated using Weblate (Thai)
Currently translated at 84.1% (5381 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/th/
2024-11-09 21:29:17 +00:00
Adam Idrici 6885569f9e Translated using Weblate (French)
Currently translated at 100.0% (6391 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-09 21:29:15 +00:00
Alexis Salgueiro 601927406c Translated using Weblate (French)
Currently translated at 100.0% (6391 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-09 21:29:15 +00:00
Natchakot Chuchokjatuporn 347b0bfa37 Translated using Weblate (Thai)
Currently translated at 81.4% (5206 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/th/
2024-11-07 23:47:02 +00:00
Alexis Salgueiro efa63b105f Translated using Weblate (French)
Currently translated at 100.0% (6391 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-07 23:47:01 +00:00
Adam Idrici 18d8c19df7 Translated using Weblate (French)
Currently translated at 100.0% (6391 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-07 23:47:01 +00:00
Natchakot Chuchokjatuporn 8d7c92f30e Translated using Weblate (Thai)
Currently translated at 80.9% (5173 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/th/
2024-11-07 22:41:43 +00:00
Alexis Salgueiro 4e7b7d8d59 Translated using Weblate (French)
Currently translated at 96.6% (6179 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-07 22:41:41 +00:00
Felipe Bermudes Ormeño 1213fc9145 Translated using Weblate (Spanish (Mexico))
Currently translated at 30.5% (1954 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/es_MX/
2024-11-07 22:41:40 +00:00
Adam Idrici 071038dc09 Translated using Weblate (French)
Currently translated at 96.6% (6176 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-04 12:28:48 +00:00
Weblate 2688e37f77 Update translation files
Updated by "Remove blank strings" add-on in Weblate.

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/
2024-11-03 22:31:01 +00:00
阿鱼 e8a9ea1185 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (6391 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/zh_Hans/
2024-11-03 22:30:58 +00:00
Alexis Salgueiro 4770c273f9 Translated using Weblate (French)
Currently translated at 96.3% (6159 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-03 22:30:55 +00:00
Adam Idrici 0e2e42b826 Translated using Weblate (French)
Currently translated at 96.3% (6159 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/fr/
2024-11-03 22:30:54 +00:00
GottvaterNougatKoenig de819828ce Translated using Weblate (German)
Currently translated at 87.5% (5597 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2024-11-03 22:30:53 +00:00
Mia fed34e9b98 Translated using Weblate (German)
Currently translated at 87.5% (5597 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/de/
2024-11-03 22:30:53 +00:00
1015 changed files with 16553 additions and 9344 deletions

No files matched your search

+18
View File
@@ -71,6 +71,7 @@
- Octillery
- Mantine
- Smeargle
- Delibird
#### Gen 3
- Slakoth
@@ -250,6 +251,7 @@
### Model updates for the following Pokémon
- Bulbasaur, Ivysaur, Venusaur
- Charmander, Charmeleon, Charizard
- Caterpie
- Kakuna, Beedrill
- Lapras
- Porygon, Porygon2, Porygon-Z
@@ -285,9 +287,11 @@
- Phantump, Trevenant
- Litten, Torracat, Incineroar
- Popplio, Brionne, Primarina
- Mudbray
- Lurantis
- Scorbunny, Cinderace
- Quaxly
- Skeledirge
- Tatsugiri
### Changes
@@ -343,6 +347,7 @@
- A short jump indicates that you caught the Pokémon.
- Pokémon sent out during battle will spawn facing their opponent.
- Pokémon sent out outside a battle will spawn facing their trainer.
- Wailord is now 25% bigger
### Fixes
- Fixed Ability Patches not reverting Hidden Abilities back to Normal Abilities.
@@ -397,6 +402,11 @@
- Fixed Alolan Exeggutor's tail not showing in the party UI. It will now also stand in front of all Pokémon in the party menu :)
- Fixed Timburr duplicating its log while fainting.
- Fixed hitbox sizes for Grotle and Torterra being set to default values.
- Fixed Hisuian Sneasel using Johtonian Sneasel's cry
- Fixed Trevenant t-posing after 8 seconds of sleep.
- Fixed Bewear t-posing for a bit if a wild one fainted.
- Fixed Noctowl's placeholder fly animation.
- Corrected Lotad's kotlin poser to use its own blink animation instead of Charmander's.
- Fixed reviving items throwing an exception when used in battle.
- Fixed messages for Focus Sash, Confusion, Mummy, Ice Face, Own Tempo, and Revive.
- Improve error handling when loading spawn-sets to ensure invalid configurations don't crash the server.
@@ -427,6 +437,8 @@
- Prevent summary stats tab from making sounds when clicking on an already open tab.
- Fixed display case not being able to be fed items from underneath.
- Fixed Pokémon battling in water continuously sinking to the bottom.
- Fixed passive healing and wake from faint not disabling when their config values are set to 0.
- Fixed an issue where rebinding the R key to a mouse button prevented players from closing the battle interface using that button.
### Developer
- `SpawnCause` is now an implementation of `SpawningInfluence`.
@@ -458,6 +470,7 @@
- Added HealingSource, an interface applied to all sources of healing from player actions, for easier tracking of healing sources.
- Move Change
- Shiny Chance Calculation Event (with player context)
- Dex Information Changed; this event is fired when the Pokédex is updated with new information.
- Rebuilt large swaths of the model animation code to simplify it.
- Renamed a bunch of things from %Poseable% to %Posable% because spelling.
- Renamed StatelessAnimation to PoseAnimation.
@@ -486,6 +499,10 @@
- Added support for conditional pose animations.
- Added a new universal locator called "top".
- Added `eggs_collected` and `eggs_hatched` Advancement triggers.
- Added missing `minYaw` configuration to the `q.look()` function for JSON posers.
- Some pose condition names have been changed:
- `isTouchingWaterOrRain` has been changed to `isInWaterOrRain`
- `isSubermegedInWater` has been changed to `isUnderWater`
### Localization
- Updated translations for:
@@ -1720,6 +1737,7 @@ Thank you so much to all of our community translators that bring the mod to the
- Lowered spawn rate of Tauros.
- Sableye now spawns near gem ores as well as amethyst.
- Added evolution stones and items to item tags
- Pokémon now play their cry animations when clicked on the starter selection screen.
### Fixes
- Fixed catch rates being entirely too difficult.
@@ -54,7 +54,10 @@ import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.api.storage.pc.link.PCLinkManager
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreManager
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreTypes
import com.cobblemon.mod.common.api.storage.player.adapter.*
import com.cobblemon.mod.common.api.storage.player.adapter.DexDataMongoBackend
import com.cobblemon.mod.common.api.storage.player.adapter.DexDataNbtBackend
import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataJsonBackend
import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataMongoBackend
import com.cobblemon.mod.common.api.storage.player.factory.CachedPlayerDataStoreFactory
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
@@ -65,16 +68,7 @@ import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.ShowdownThread
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.command.argument.DexArgumentType
import com.cobblemon.mod.common.command.argument.DialogueArgumentType
import com.cobblemon.mod.common.command.argument.FormArgumentType
import com.cobblemon.mod.common.command.argument.MoveArgumentType
import com.cobblemon.mod.common.command.argument.NPCClassArgumentType
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType
import com.cobblemon.mod.common.command.argument.PokemonStoreArgumentType
import com.cobblemon.mod.common.command.argument.SpawnBucketArgumentType
import com.cobblemon.mod.common.command.argument.SpeciesArgumentType
import com.cobblemon.mod.common.command.argument.*
import com.cobblemon.mod.common.config.CobblemonConfig
import com.cobblemon.mod.common.config.LastChangedVersion
import com.cobblemon.mod.common.config.constraint.IntConstraint
@@ -94,17 +88,21 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
import com.cobblemon.mod.common.pokemon.properties.FreezeFrameProperty
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.trade.TradeManager
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.ifDedicatedServer
import com.cobblemon.mod.common.util.isLaterVersion
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
@@ -116,7 +114,7 @@ import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.*
import java.util.UUID
import kotlin.math.roundToInt
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
@@ -386,8 +384,13 @@ object Cobblemon {
BattleFormat.GEN_9_SINGLES,
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
true
).ifSuccessful { it.mute = true }
false
).ifSuccessful {
it.mute = true
}.ifErrored {
val errors = it.errors.joinToString("\n") { it.javaClass.name }
LOGGER.error("Failed to start dummy Showdown battle: $errors")
}
}
registerEventHandlers()
@@ -276,6 +276,81 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val CHISELED_BLACK_TUMBLESTONE_BRICKS = this.create("chiseled_black_tumblestone_bricks", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_BUG_BLOCK = this.create("gem_bug_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_DARK_BLOCK = this.create("gem_dark_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_DRAGON_BLOCK = this.create("gem_dragon_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_ELECTRIC_BLOCK = this.create("gem_electric_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_FAIRY_BLOCK = this.create("gem_fairy_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_FIGHTING_BLOCK = this.create("gem_fighting_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_FIRE_BLOCK = this.create("gem_fire_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_FLYING_BLOCK = this.create("gem_flying_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_GHOST_BLOCK = this.create("gem_ghost_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_GRASS_BLOCK = this.create("gem_grass_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_GROUND_BLOCK = this.create("gem_ground_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_ICE_BLOCK = this.create("gem_ice_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_NORMAL_BLOCK = this.create("gem_normal_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_POISON_BLOCK = this.create("gem_poison_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_PSYCHIC_BLOCK = this.create("gem_psychic_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_ROCK_BLOCK = this.create("gem_rock_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_STEEL_BLOCK = this.create("gem_steel_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_WATER_BLOCK = this.create("gem_water_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_BUG_BUDDING = this.create("gem_bug_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_DARK_BUDDING = this.create("gem_dark_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_DRAGON_BUDDING = this.create("gem_dragon_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_ELECTRIC_BUDDING = this.create("gem_electric_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_FAIRY_BUDDING = this.create("gem_fairy_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_FIGHTING_BUDDING = this.create("gem_fighting_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_FIRE_BUDDING = this.create("gem_fire_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_FLYING_BUDDING = this.create("gem_flying_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_GHOST_BUDDING = this.create("gem_ghost_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_GRASS_BUDDING = this.create("gem_grass_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_GROUND_BUDDING = this.create("gem_ground_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_ICE_BUDDING = this.create("gem_ice_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_NORMAL_BUDDING = this.create("gem_normal_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_POISON_BUDDING = this.create("gem_poison_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_PSYCHIC_BUDDING = this.create("gem_psychic_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_ROCK_BUDDING = this.create("gem_rock_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_STEEL_BUDDING = this.create("gem_steel_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val GEM_WATER_BUDDING = this.create("gem_water_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
@JvmField
val FIRE_STONE_BLOCK = this.create("fire_stone_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.FIRE).strength(1.0F).sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BIT).lightLevel{13}))
@JvmField
@@ -56,6 +56,7 @@ object CobblemonCommands {
AbandonMultiTeam.register(dispatcher)
FreezePokemonCommand.register(dispatcher)
ApplyPlayerTextureCommand.register(dispatcher)
RunMolangScriptCommand.register(dispatcher)
// Possibly lock down registration if and only if under dev environment or running in an environment
// with a certain system environment variable set
@@ -48,6 +48,8 @@ object CobblemonFlows : DataRegistry {
val flows = hashMapOf<ResourceLocation, MutableList<ExpressionLike>>()
override fun reload(manager: ResourceManager) {
clientFlows.clear()
flows.clear()
val folderBeforeNameRegex = ".*\\/([^\\/]+)\\/[^\\/]+\$".toRegex()
manager.listResources("flows") { path -> path.endsWith(CobblemonScripts.MOLANG_EXTENSION) }.forEach { (identifier, resource) ->
resource.openAsReader().use { stream ->
@@ -54,6 +54,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
override val registry: Registry<Item> = BuiltInRegistries.ITEM
override val resourceKey: ResourceKey<Registry<Item>> = Registries.ITEM
@JvmField
val NPC_EDITOR = create("npc_editor", CobblemonItem(Item.Properties().stacksTo(1)))
@JvmField
val pokeBalls = mutableListOf<PokeBallItem>()
@JvmField
@@ -1224,6 +1227,80 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
//@JvmField
//val BINDING_SOIL = blockItem("binding_soil", CobblemonBlocks.BINDING_SOIL)
@JvmField
val GEM_BUG_BLOCK = blockItem("gem_bug_block", CobblemonBlocks.GEM_BUG_BLOCK)
@JvmField
val GEM_DARK_BLOCK = blockItem("gem_dark_block", CobblemonBlocks.GEM_DARK_BLOCK)
@JvmField
val GEM_DRAGON_BLOCK = blockItem("gem_dragon_block", CobblemonBlocks.GEM_DRAGON_BLOCK)
@JvmField
val GEM_ELECTRIC_BLOCK = blockItem("gem_electric_block", CobblemonBlocks.GEM_ELECTRIC_BLOCK)
@JvmField
val GEM_FAIRY_BLOCK = blockItem("gem_fairy_block", CobblemonBlocks.GEM_FAIRY_BLOCK)
@JvmField
val GEM_FIGHTING_BLOCK = blockItem("gem_fighting_block", CobblemonBlocks.GEM_FIGHTING_BLOCK)
@JvmField
val GEM_FIRE_BLOCK = blockItem("gem_fire_block", CobblemonBlocks.GEM_FIRE_BLOCK)
@JvmField
val GEM_FLYING_BLOCK = blockItem("gem_flying_block", CobblemonBlocks.GEM_FLYING_BLOCK)
@JvmField
val GEM_GHOST_BLOCK = blockItem("gem_ghost_block", CobblemonBlocks.GEM_GHOST_BLOCK)
@JvmField
val GEM_GRASS_BLOCK = blockItem("gem_grass_block", CobblemonBlocks.GEM_GRASS_BLOCK)
@JvmField
val GEM_GROUND_BLOCK = blockItem("gem_ground_block", CobblemonBlocks.GEM_GROUND_BLOCK)
@JvmField
val GEM_ICE_BLOCK = blockItem("gem_ice_block", CobblemonBlocks.GEM_ICE_BLOCK)
@JvmField
val GEM_NORMAL_BLOCK = blockItem("gem_normal_block", CobblemonBlocks.GEM_NORMAL_BLOCK)
@JvmField
val GEM_POISON_BLOCK = blockItem("gem_poison_block", CobblemonBlocks.GEM_POISON_BLOCK)
@JvmField
val GEM_PSYCHIC_BLOCK = blockItem("gem_psychic_block", CobblemonBlocks.GEM_PSYCHIC_BLOCK)
@JvmField
val GEM_ROCK_BLOCK = blockItem("gem_rock_block", CobblemonBlocks.GEM_ROCK_BLOCK)
@JvmField
val GEM_STEEL_BLOCK = blockItem("gem_steel_block", CobblemonBlocks.GEM_STEEL_BLOCK)
@JvmField
val GEM_WATER_BLOCK = blockItem("gem_water_block", CobblemonBlocks.GEM_WATER_BLOCK)
@JvmField
val GEM_BUG_BUDDING = blockItem("gem_bug_budding", CobblemonBlocks.GEM_BUG_BUDDING)
@JvmField
val GEM_DARK_BUDDING = blockItem("gem_dark_budding", CobblemonBlocks.GEM_DARK_BUDDING)
@JvmField
val GEM_DRAGON_BUDDING = blockItem("gem_dragon_budding", CobblemonBlocks.GEM_DRAGON_BUDDING)
@JvmField
val GEM_ELECTRIC_BUDDING = blockItem("gem_electric_budding", CobblemonBlocks.GEM_ELECTRIC_BUDDING)
@JvmField
val GEM_FAIRY_BUDDING = blockItem("gem_fairy_budding", CobblemonBlocks.GEM_FAIRY_BUDDING)
@JvmField
val GEM_FIGHTING_BUDDING = blockItem("gem_fighting_budding", CobblemonBlocks.GEM_FIGHTING_BUDDING)
@JvmField
val GEM_FIRE_BUDDING = blockItem("gem_fire_budding", CobblemonBlocks.GEM_FIRE_BUDDING)
@JvmField
val GEM_FLYING_BUDDING = blockItem("gem_flying_budding", CobblemonBlocks.GEM_FLYING_BUDDING)
@JvmField
val GEM_GHOST_BUDDING = blockItem("gem_ghost_budding", CobblemonBlocks.GEM_GHOST_BUDDING)
@JvmField
val GEM_GRASS_BUDDING = blockItem("gem_grass_budding", CobblemonBlocks.GEM_GRASS_BUDDING)
@JvmField
val GEM_GROUND_BUDDING = blockItem("gem_ground_budding", CobblemonBlocks.GEM_GROUND_BUDDING)
@JvmField
val GEM_ICE_BUDDING = blockItem("gem_ice_budding", CobblemonBlocks.GEM_ICE_BUDDING)
@JvmField
val GEM_NORMAL_BUDDING = blockItem("gem_normal_budding", CobblemonBlocks.GEM_NORMAL_BUDDING)
@JvmField
val GEM_POISON_BUDDING = blockItem("gem_poison_budding", CobblemonBlocks.GEM_POISON_BUDDING)
@JvmField
val GEM_PSYCHIC_BUDDING = blockItem("gem_psychic_budding", CobblemonBlocks.GEM_PSYCHIC_BUDDING)
@JvmField
val GEM_ROCK_BUDDING = blockItem("gem_rock_budding", CobblemonBlocks.GEM_ROCK_BUDDING)
@JvmField
val GEM_STEEL_BUDDING = blockItem("gem_steel_budding", CobblemonBlocks.GEM_STEEL_BUDDING)
@JvmField
val GEM_WATER_BUDDING = blockItem("gem_water_budding", CobblemonBlocks.GEM_WATER_BUDDING)
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Properties()))
private fun noSettingsItem(name: String): CobblemonItem = this.create(name, CobblemonItem(Item.Properties()))
@@ -55,6 +55,8 @@ object CobblemonCriteria : PlatformRegistry<Registry<CriterionTrigger<*>>, Resou
val CAST_POKE_ROD = this.create("cast_poke_rod", SimpleCriterionTrigger(CastPokeRodCriterionCondition.CODEC))
val REEL_IN_POKEMON = this.create("reel_in_pokemon", SimpleCriterionTrigger(ReelInPokemonCriterionCondition.CODEC))
// Advancement criteria for [grow_tumblestone.json]
val PLANT_TUMBLESTONE = this.create("plant_tumblestone", SimpleCriterionTrigger(PlantTumblestoneCriterion.CODEC))
@@ -8,26 +8,30 @@
package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
class CastPokeRodContext(val baitId: ResourceLocation)
class CastPokeRodCriterionCondition(
playerCtx: Optional<ContextAwarePredicate>,
val hasBait: Boolean
): SimpleCriterionCondition<Boolean>(playerCtx) {
playerCtx: Optional<ContextAwarePredicate>,
val baitId: String
): SimpleCriterionCondition<CastPokeRodContext>(playerCtx) {
companion object {
val CODEC: Codec<CastPokeRodCriterionCondition> = RecordCodecBuilder.create { it.group(
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(CastPokeRodCriterionCondition::playerCtx),
PrimitiveCodec.BOOL.fieldOf("hasBait").forGetter(CastPokeRodCriterionCondition::hasBait)
).apply(it, ::CastPokeRodCriterionCondition) }
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(CastPokeRodCriterionCondition::playerCtx),
Codec.STRING.optionalFieldOf("baitId", "empty_bait").forGetter(CastPokeRodCriterionCondition::baitId)
).apply(it, { playerCtx, baitId -> CastPokeRodCriterionCondition(playerCtx, baitId.ifEmpty { "empty_bait" }) }) }
}
override fun matches(player: ServerPlayer, context: Boolean): Boolean {
return hasBait == context
override fun matches(player: ServerPlayer, context: CastPokeRodContext): Boolean {
return (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId.equals("empty_bait"))
}
}
}
@@ -26,7 +26,7 @@ class PartyCheckCriterion(
companion object {
val CODEC: Codec<PartyCheckCriterion> = RecordCodecBuilder.create { it.group(
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(PartyCheckCriterion::playerCtx),
ResourceLocation.CODEC.listOf().optionalFieldOf("id", listOf()).forGetter(PartyCheckCriterion::party)
ResourceLocation.CODEC.listOf().optionalFieldOf("party", listOf()).forGetter(PartyCheckCriterion::party)
).apply(it, ::PartyCheckCriterion) }
}
@@ -44,7 +44,7 @@ class PartyCheckCriterion(
matches.add(it.species.resourceIdentifier)
}
}
return matches.containsAll(party) && matches.size == partyCount
return matches.containsAll(party) && matches.size == party.size
}
}
@@ -0,0 +1,39 @@
/*
* 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.advancement.criterion
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.server.level.ServerPlayer
import net.minecraft.resources.ResourceLocation
class ReelInPokemonContext(val pokemonId : ResourceLocation, val baitId: ResourceLocation)
class ReelInPokemonCriterionCondition(
playerCtx: Optional<ContextAwarePredicate>,
val pokemonId: String,
val baitId: String
) : SimpleCriterionCondition<ReelInPokemonContext>(playerCtx) {
companion object {
val CODEC: Codec<ReelInPokemonCriterionCondition> = RecordCodecBuilder.create { it.group(
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter { it.playerCtx },
Codec.STRING.optionalFieldOf("pokemonId", "any").forGetter { it.pokemonId },
Codec.STRING.optionalFieldOf("baitId", "empty_bait").forGetter { it.baitId }
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId.ifEmpty { "empty_bait" }) }) }
}
override fun matches(player: ServerPlayer, context: ReelInPokemonContext): Boolean {
return (context.pokemonId == this.pokemonId.asIdentifierDefaultingNamespace() || this.pokemonId == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
}
}
@@ -61,7 +61,7 @@ open class ItemDropEntry : DropEntry {
if (dropMethod == ItemDropMethod.ON_PLAYER && player != null) {
world.addFreshEntity(ItemEntity(player.level(), player.x, player.y, player.z, stack))
} else if (dropMethod == ItemDropMethod.TO_INVENTORY && player != null) {
} else if (dropMethod == ItemDropMethod.TO_INVENTORY && player != null && !stack.isEmpty) {
val name = stack.hoverName
val count = stack.count
val succeeded = player.addItem(stack)
@@ -192,6 +192,8 @@ object CobblemonEvents {
val POKEMON_GAINED = EventObservable<PokemonGainedEvent>()
@JvmField
val POKEMON_SEEN = EventObservable<PokemonSeenEvent>()
@JvmField
val POKEDEX_DATA_CHANGED = EventObservable<PokedexDataChangedEvent>()
// Fishing
@JvmField
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.pokemon
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokedex.FormDexRecord
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.getPlayer
import com.mojang.datafixers.util.Either
import java.util.UUID
/**
* Event that fires when a Pokémon's information is gained or updated in the Pokédex.
*/
data class PokedexDataChangedEvent(
val dataSource: Either<PokedexEntityData, Pokemon>,
val knowledge: PokedexEntryProgress,
val playerUUID: UUID,
val record: FormDexRecord
) {
val pokedexManager: AbstractPokedexManager
get() = record.speciesDexRecord.pokedexManager
val context = mutableMapOf<String, MoValue>(
"player" to (playerUUID.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
"pokemon" to dataSource.map({ DoubleValue.ZERO }, { it.struct }),
"data" to dataSource.map({ it.struct }, { DoubleValue.ZERO }),
"knowledge" to StringValue(knowledge.name.lowercase()),
"pokedex" to pokedexManager.struct
)
}
@@ -14,5 +14,4 @@ import java.util.UUID
data class PokemonGainedEvent(
val playerId: UUID,
val pokemon: Pokemon
) {
}
)
@@ -9,11 +9,9 @@
package com.cobblemon.mod.common.api.events.pokemon
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.level.ServerPlayer
import java.util.UUID
data class PokemonSeenEvent(
val playerId: UUID,
val pokemon: Pokemon
) {
}
)
@@ -8,6 +8,7 @@
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
@@ -22,7 +23,7 @@ abstract class ParentWidget(
pX: Int, pY: Int,
pWidth: Int, pHeight: Int,
component: Component
): Renderable, AbstractWidget(pX, pY, pWidth, pHeight, component) {
): CobblemonRenderable, AbstractWidget(pX, pY, pWidth, pHeight, component) {
val children: MutableList<GuiEventListener> = mutableListOf()
@@ -74,7 +74,7 @@ abstract class RequestManager<T : ServerPlayerActionRequest> {
?: this.getInboundRequest(receiver.uuid, requestID)
/** Determines whether [player] can receive a [T]. */
open fun isBusy(player: ServerPlayer): Boolean = player.isInBattle() || player.isTrading()
open fun isBusy(player: ServerPlayer): Boolean = player.isInBattle() || player.isTrading() || player.party().find { it.entity?.isBusy == true } != null
/** Determines if the [target] is a valid interaction request target. */
abstract fun isValidInteraction(player: ServerPlayer, target: ServerPlayer): Boolean
@@ -176,7 +176,7 @@ abstract class RequestManager<T : ServerPlayerActionRequest> {
else if (!this.isValidInteraction(player, target ?: request.sender)) // with teams anyone can accept
request.notify(player, true, "ui.interact.failed")
// if sending player is occupied, can't accept response
else if (this.isBusy(request.sender)) // TODO enhancement: allow retries - modify client so we don't remove request when sending acceptance
else if (this.isBusy(request.sender) || this.isBusy(request.receiver)) // TODO enhancement: allow retries - modify client so we don't remove request when sending acceptance
request.notify(player, true, "ui.interact.unavailable")
// if no condition is blocking acceptance, accept
else if (this.canAccept(request))
@@ -38,8 +38,9 @@ import net.minecraft.world.phys.AABB
*/
interface PokemonSelectingItem {
fun use(player: ServerPlayer, stack: ItemStack): InteractionResultHolder<ItemStack> {
val range = player.entityInteractionRange()
val entity = player.level()
.getEntities(player, AABB.ofSize(player.position(), 16.0, 16.0, 16.0))
.getEntities(player, AABB.ofSize(player.position(), range, range, range))
.filter { player.isLookingAt(it, stepDistance = 0.1F) }
.minByOrNull { it.distanceTo(player) } as? PokemonEntity?
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.item.ability
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.abilities.*
import com.cobblemon.mod.common.item.interactive.ability.AbilityTypeChanger
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -33,7 +34,7 @@ interface AbilityChanger<T : PotentialAbility> {
* @param pokemon The [Pokemon] being queried.
* @return A set containing all their legal abilities associated with [type], can be empty.
*/
fun queryPossible(pokemon: Pokemon): Set<AbilityTemplate>
fun queryPossible(pokemon: Pokemon): Set<Pair<AbilityTemplate, Priority>>
/**
* Attempts to update the ability of the given [pokemon].
@@ -29,6 +29,13 @@ import com.cobblemon.mod.common.api.dialogue.ReferenceDialogueFaceProvider
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.api.moves.animations.NPCProvider
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.CaughtCount
import com.cobblemon.mod.common.api.pokedex.CaughtPercent
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.api.pokedex.PokedexManager
import com.cobblemon.mod.common.api.pokedex.SeenCount
import com.cobblemon.mod.common.api.pokedex.SeenPercent
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
@@ -40,6 +47,8 @@ import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
import com.cobblemon.mod.common.client.particle.ParticleStorm
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
@@ -49,11 +58,15 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.*
import com.mojang.datafixers.util.Either
import java.util.UUID
import kotlin.math.sqrt
import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.commands.arguments.EntityAnchorArgument
import net.minecraft.core.BlockPos
import net.minecraft.core.Holder
@@ -102,6 +115,12 @@ object MoLangFunctions {
val message = params.get<MoValue>(0).asString()
Cobblemon.LOGGER.info(message)
},
"set_query" to java.util.function.Function { params ->
val variable = params.getString(0)
val value = params.get<MoValue>(1)
params.environment.query.addFunction(variable) { value }
return@Function value
},
"replace" to java.util.function.Function { params ->
val text = params.getString(0)
val search = params.getString(1)
@@ -221,6 +240,31 @@ object MoLangFunctions {
world.addFreshEntity(lightning)
return@put DoubleValue.ONE
}
// q.entity.world.spawn_bedrock_particles(effect, x, y, z, [player]) - sends to everyone nearby or just to the player if they're set.
map.put("spawn_bedrock_particles") { params ->
val particle = params.getString(0).asResource()
val x = params.getDouble(1)
val y = params.getDouble(2)
val z = params.getDouble(3)
val player = params.getOrNull<MoValue>(4)?.let {
if (it is StringValue) world.getPlayerByUUID(UUID.fromString(it.value))
else if (it is ObjectValue<*>) it.obj
else null
} as? ServerPlayer
val pos = Vec3(x, y, z)
if (world !is ClientLevel) {
val packet = SpawnSnowstormParticlePacket(particle, pos)
if (player != null) {
packet.sendToPlayer(player)
} else {
packet.sendToPlayersAround(x, y, z, 64.0, world.dimension())
}
} else {
val effect = BedrockParticleOptionsRepository.getEffect(particle) ?: return@put DoubleValue.ZERO
ParticleStorm.createAtPosition(world, effect, pos).spawn()
}
}
map.put("get_entities_around") { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
@@ -320,6 +364,8 @@ object MoLangFunctions {
val data = Cobblemon.molangData.load(player.uuid)
if (data.map.containsKey(npcId)) {
return@put (data.map[npcId] as VariableStruct).map[variable] ?: DoubleValue.ZERO
} else {
return@put DoubleValue.ZERO
}
}
map.put("set_npc_variable") { params ->
@@ -328,16 +374,14 @@ object MoLangFunctions {
val value = params.get<MoValue>(2)
val saveAfterwards = params.getBooleanOrNull(3) != false
val data = Cobblemon.molangData.load(player.uuid)
if (data.map.containsKey(npcId)) {
(data.map[npcId] as VariableStruct).map[variable] = value
if (saveAfterwards) {
Cobblemon.molangData.save(player.uuid)
}
return@put DoubleValue.ONE
} else {
return@put DoubleValue.ZERO
val npcData = data.map.getOrPut(npcId) { VariableStruct() } as VariableStruct
npcData.map[variable] = value
if (saveAfterwards) {
Cobblemon.molangData.save(player.uuid)
}
return@put DoubleValue.ONE
}
map.put("pokedex") { player.pokedex().struct }
}
map
}
@@ -445,7 +489,42 @@ object MoLangFunctions {
map.put("play_animation") { params ->
val animation = params.getString(0)
val packet = PlayPosableAnimationPacket(entity.id, setOf(animation), emptyList())
val target = params.getStringOrNull(1)
if (target != null) {
val targetPlayer = if (target.asUUID != null) {
entity.level().getPlayerByUUID(target.asUUID!!) as ServerPlayer
} else if (entity.level() is ServerLevel) {
entity.level().server!!.playerList.getPlayerByName(target)
} else {
null
}
if (targetPlayer != null) {
packet.sendToPlayer(targetPlayer)
return@put DoubleValue.ONE
} else {
return@put DoubleValue.ZERO
}
} else {
packet.sendToPlayersAround(entity.x, entity.y, entity.z, 64.0, entity.level().dimension())
return@put DoubleValue.ONE
}
}
}
// q.entity.spawn_bedrock_particles(effect, locator, [player]) - sends to everyone nearby or just to the player if they're set. Locator is necessary even if unused on non-posables.
map.put("spawn_bedrock_particles") { params ->
val particle = params.getString(0).asResource()
val locator = params.getString(1)
val player = params.getOrNull<MoValue>(2)?.let {
if (it is StringValue) entity.level().getPlayerByUUID(UUID.fromString(it.value))
else if (it is ObjectValue<*>) it.obj
else null
} as? ServerPlayer
val packet = SpawnSnowstormEntityParticlePacket(particle, entity.id, listOf(locator))
if (player == null) {
packet.sendToPlayersAround(entity.x, entity.y, entity.z, 64.0, entity.level().dimension())
} else {
packet.sendToPlayer(player)
}
}
map
@@ -594,6 +673,7 @@ object MoLangFunctions {
}
map.put("is_wild") { DoubleValue(pokemon.entity?.let { it.ownerUUID == null } == true) }
map.put("is_shiny") { DoubleValue(pokemon.shiny) }
map.put("species") { pokemon.species.struct }
map.put("form") { StringValue(pokemon.form.name) }
map.put("weight") { DoubleValue(pokemon.species.weight.toDouble()) }
map.put("matches") { params -> DoubleValue(params.getString(0).toProperties().matches(pokemon)) }
@@ -804,6 +884,78 @@ object MoLangFunctions {
}
)
val pokedexFunctions: MutableList<(AbstractPokedexManager) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
{ pokedex ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("get_species_record") { params ->
val speciesId = params.getString(0).asIdentifierDefaultingNamespace()
pokedex.speciesRecords[speciesId]?.struct ?: QueryStruct(hashMapOf())
}
map.put("has_seen") { params ->
val speciesId = params.getString(0).asIdentifierDefaultingNamespace()
val formName = params.getStringOrNull(1)
if (formName == null) {
return@put DoubleValue(pokedex.getHighestKnowledgeForSpecies(speciesId).ordinal >= PokedexEntryProgress.ENCOUNTERED.ordinal)
} else {
return@put DoubleValue((pokedex.getSpeciesRecord(speciesId)?.getFormRecord(formName)?.knowledge?.ordinal ?: 0) >= PokedexEntryProgress.ENCOUNTERED.ordinal)
}
}
map.put("has_caught") { params ->
val speciesId = params.getString(0).asIdentifierDefaultingNamespace()
val formName = params.getStringOrNull(1)
if (formName == null) {
return@put DoubleValue(pokedex.getHighestKnowledgeForSpecies(speciesId) == PokedexEntryProgress.CAUGHT)
} else {
return@put DoubleValue(pokedex.getSpeciesRecord(speciesId)?.getFormRecord(formName)?.knowledge == PokedexEntryProgress.CAUGHT)
}
}
map.put("caught_count") { DoubleValue(pokedex.getGlobalCalculatedValue(CaughtCount)) }
map.put("seen_count") { DoubleValue(pokedex.getGlobalCalculatedValue(SeenCount)) }
map.put("caught_percent") { DoubleValue(pokedex.getGlobalCalculatedValue(CaughtPercent)) }
map.put("seen_percent") { DoubleValue(pokedex.getGlobalCalculatedValue(SeenPercent)) }
if (pokedex is PokedexManager) {
map.put("player_id") { StringValue(pokedex.uuid.toString()) }
map.put("see") { params ->
val pokemon = params.get<ObjectValue<Pokemon>>(0).obj
pokedex.encounter(pokemon)
return@put DoubleValue.ONE
}
map.put("catch") { params ->
val pokemon = params.get<ObjectValue<Pokemon>>(0).obj
pokedex.catch(pokemon)
return@put DoubleValue.ONE
}
}
map
}
)
val speciesFunctions: MutableList<(Species) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
{ species ->
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
map.put("identifier") { StringValue(species.resourceIdentifier.toString()) }
map.put("name") { StringValue(species.name) }
map.put("primary_type") { StringValue(species.primaryType.name) }
map.put("secondary_type") { StringValue(species.secondaryType?.name ?: "null") }
map.put("experience_group") { StringValue(species.experienceGroup.name) }
map.put("height") { DoubleValue(species.height) }
map.put("weight") { DoubleValue(species.weight) }
map.put("base_scale") { DoubleValue(species.baseScale) }
map.put("hitbox_width") { DoubleValue(species.hitbox.width) }
map.put("hitbox_height") { DoubleValue(species.hitbox.height) }
map.put("hitbox_fixed") { DoubleValue(species.hitbox.fixed) }
map.put("catch_rate") { DoubleValue(species.catchRate) }
map
}
)
fun Holder<Biome>.asBiomeMoLangValue() = asMoLangValue(Registries.BIOME).addFunctions(biomeFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
fun Holder<Level>.asWorldMoLangValue() = asMoLangValue(Registries.DIMENSION).addFunctions(worldFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
fun Holder<Block>.asBlockMoLangValue() = asMoLangValue(Registries.BLOCK).addFunctions(blockFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
@@ -935,6 +1087,22 @@ object MoLangFunctions {
return this
}
fun QueryStruct.addPokedexFunctions(pokedexManager: AbstractPokedexManager): QueryStruct {
val addedFunctions = pokedexFunctions
.flatMap { it.invoke(pokedexManager).entries }
.associate { it.key to it.value }
functions.putAll(addedFunctions)
return this
}
fun QueryStruct.addSpeciesFunctions(species: Species): QueryStruct {
val addedFunctions = speciesFunctions
.flatMap { it.invoke(species).entries }
.associate { it.key to it.value }
functions.putAll(addedFunctions)
return this
}
fun QueryStruct.addPokemonFunctions(pokemon: Pokemon): QueryStruct {
val addedFunctions = pokemonFunctions
.flatMap { it.invoke(pokemon).entries }
@@ -36,7 +36,7 @@ class AnimationActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityC
// Treat them as expressions if possible but otherwise yeah just send them as strings
val animation = animation.map {
try {
it.asExpressionLike().resolveString(context.runtime).takeIf { it != "0.0" } ?: it
it.asExpressionLike().resolveString(context.runtime).takeIf { it != "0" } ?: it
} catch (e: Exception) {
it
}
@@ -42,7 +42,7 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
val effectIdentifier = try {
effect?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0.0" } ?: effect
effect?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0" } ?: effect
} catch (e: Exception) {
effect
}?.asIdentifierDefaultingNamespace() ?: return skip()
@@ -35,7 +35,7 @@ class EntitySoundActionEffectKeyframe : ConditionalActionEffectKeyframe(), Entit
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
val soundIdentifier = try {
sound?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0.0" } ?: sound
sound?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0" } ?: sound
} catch (e: Exception) {
sound
}?.asIdentifierDefaultingNamespace() ?: return skip()
@@ -38,7 +38,8 @@ class NPCClass {
var resourceIdentifier: ResourceLocation = cobblemonResource("dummy")
var names: MutableList<Component> = mutableListOf()
var aspects: MutableSet<String> = mutableSetOf() // These only make sense when applied via presets
var hitbox = EntityDimensions.scalable(0.6F, 1.8F)
var hitbox = EntityDimensions.scalable(0.6F, 1.8F).withEyeHeight(1.62F)
var modelScale: Float = 0.94F
var battleConfiguration = NPCBattleConfiguration()
var interaction: NPCInteractConfiguration? = null
var canDespawn = true
@@ -48,6 +49,7 @@ class NPCClass {
var party: NPCPartyProvider? = null
var skill: Int = 0
var autoHealParty: Boolean = true
var randomizePartyOrder: Boolean = false
var battleTheme: ResourceLocation? = null
var ai: MutableList<BrainConfig> = mutableListOf()
var isMovable: Boolean = true
@@ -60,9 +62,9 @@ class NPCClass {
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeString(resourceIdentifier.toString())
buffer.writeCollection(names) { _, v -> buffer.writeText(v) }
buffer.writeFloat(this.hitbox.width)
buffer.writeFloat(this.hitbox.height)
buffer.writeBoolean(this.hitbox.fixed)
buffer.writeFloat(hitbox.width)
buffer.writeFloat(hitbox.height)
buffer.writeBoolean(hitbox.fixed)
battleConfiguration.encode(buffer)
buffer.writeNullable(interaction) { _, value ->
buffer.writeString(value.type)
@@ -83,6 +85,7 @@ class NPCClass {
}
buffer.writeInt(skill)
buffer.writeBoolean(autoHealParty)
buffer.writeBoolean(randomizePartyOrder)
buffer.writeMapK(size = IntSize.U_BYTE, map = variables) { (key, value) ->
buffer.writeString(key)
buffer.writeString(value.asString())
@@ -127,6 +130,7 @@ class NPCClass {
}.toMutableList()
skill = buffer.readInt()
autoHealParty = buffer.readBoolean()
randomizePartyOrder = buffer.readBoolean()
buffer.readMapK(size = IntSize.U_BYTE, map = variables) {
val key = buffer.readString()
val value = buffer.readString()
@@ -30,6 +30,7 @@ class NPCPreset {
var ai: List<BrainConfig>? = null
var skill: Int? = null
var autoHealParty: Boolean? = null
var randomizePartyOrder: Boolean? = null
var battleTheme: ResourceLocation? = null
var isMovable: Boolean? = null
var isInvulnerable: Boolean? = null
@@ -53,6 +54,7 @@ class NPCPreset {
hitbox?.let { npcClass.hitbox = it }
skill?.let { npcClass.skill = it }
autoHealParty?.let { npcClass.autoHealParty = it }
randomizePartyOrder?.let { npcClass.randomizePartyOrder = it }
battleTheme?.let { npcClass.battleTheme = it }
ai?.let { npcClass.ai.addAll(it) }
isMovable?.let { npcClass.isMovable = it }
@@ -77,6 +77,7 @@ any number of presets and the properties of those presets will be merged into th
"canDespawn": false,
"skill": 5,
"autoHealParty": true,
"randomizePartyOrder": true,
"party": {
"type": "simple",
"pokemon": [
@@ -282,15 +283,20 @@ is not mentioned in the Pokémon properties will be set to the seed level.
The "pool" party type is a way to define a party of Pokémon using a more complicated format that involves some
randomization and weighting to different Pokémon options.
A pool party provider can be static or dynamic depending on the value of `isStatic`. It specifies the minimum
and maximum number of Pokémon that can be in the party using `minPokemon` and `maxPokemon`. The `pool` property dictates all of the possible Pokémon, with
each being an object with several properties.
A pool party provider can be static or dynamic depending on the value of `isStatic`. If `useFixedRandom` is true, the Pokémon it selects
from the pool will be constant for a single spawned NPC entity. This is slightly different to a static party because
the level of the Pokémon can still be modified dynamically using MoLang values inside each entry's `level` field.
The pool specifies the minimum and maximum number of Pokémon that can be in the party using `minPokemon` and `maxPokemon`.
The `pool` property dictates all the possible Pokémon with each being an object with several properties.
- The `pokemon` property is the Pokémon properties as used in commands and spawn files that will generate the Pokémon.
- The `weight` property is a decimal number that represents how likely that Pokémon is to be chosen. If the weight is -1, it will be guaranteed to be selected. Defaults to 1. The larger the value, the more likely it will be chosen.
- The `selectableTimes` property is the maximum number of times that the entry can be selected in the party. Defaults to 1.
- The `npcLevels` property is a range of seed levels that the Pokémon can be generated at. For example, if the NPC is spawned with seed level 10, and the range is 5-9, the Pokémon will not be selected. The actual level of the Pokémon will be the seed level. Defaults to "1-100".
- The `levelVariation` property is the amount of variation the Pokémon's level can have from the NPC seed level. For example, a value of 2 will mean that for an NPC generated with seed level 10, the Pokémon will be generated somewhere between level 8 and 12 inclusive. Defaults to zero.
- The `level` property can be used instead of `levelVariation` to force a specific level. This is a MoLang expression.
For `minPokemon`, `maxPokemon`, `weight`, `selectableTimes`, and `levelVariation`, the values can be a simple number or be full MoLang expressions. At the time
of seeding an NPC, the cosmetic variations have already been applied. Therefore, it's possible to make these properties
@@ -306,7 +312,8 @@ a single battle challenge and this is a dynamic party, there will also be a `q.p
"type": "pool",
"minPokemon": "3",
"maxPokemon": "6",
"isStatic": true,
"isStatic": false,
"useFixedRandom": true,
"pool": [
{
"pokemon": "weedle",
@@ -343,7 +350,9 @@ a single battle challenge and this is a dynamic party, there will also be a `q.p
"pokemon": "butterfree",
"weight": "5",
"npcLevels": "10-15",
"selectableTimes": "1"
"selectableTimes": "1",
"level": "q.player.party.highest_level"
}
]
}
@@ -395,6 +404,11 @@ the NPC and move them using leads.
Controls whether the NPC can be hit by projectiles. Disabling this option prevents unwanted
interactions, such as players moving the NPC with fishing rods or other projectiles.
### randomizePartyOrder
Whether the NPC's party order will be randomized between battles. When true, this NPC's party (regardless of
whether it was dynamic or static) will choose its initial send-out Pokémon randomly instead of always choosing the first
Pokémon in the party.
### ai
The AI property is an array of brain configurations. This is used to configure the behaviours of the NPC. See
the documentation for brain configurations at [AI Configuration](../ai/config/README.md).
@@ -26,6 +26,7 @@ import com.cobblemon.mod.common.util.withQueryValue
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import kotlin.random.Random
import net.minecraft.server.level.ServerPlayer
/**
@@ -50,6 +51,7 @@ class PoolPartyProvider : NPCPartyProvider {
override val type = TYPE
override var isStatic: Boolean = false
var useFixedRandom: Boolean = false
var minPokemon: Expression = "1".asExpression()
var maxPokemon: Expression = "6".asExpression()
var pool = mutableListOf<DynamicPokemon>()
@@ -63,6 +65,7 @@ class PoolPartyProvider : NPCPartyProvider {
return@map DynamicPokemon(
PokemonProperties.parse(it.asString),
"0".asExpression(),
null,
1..100,
"1".asExpression(),
"1".asExpression()
@@ -71,19 +74,22 @@ class PoolPartyProvider : NPCPartyProvider {
it as JsonObject
DynamicPokemon(
PokemonProperties.parse(it.getAsJsonPrimitive("pokemon").asString),
it.getAsJsonPrimitive("levelVariation")?.asString?.asExpression() ?: "0".asExpression(),
it.getAsJsonPrimitive("npcLevels")?.asString?.split("-")?.let { it[0].toInt()..it[1].toInt() } ?: 1..100,
it.getAsJsonPrimitive("selectableTimes")?.asString?.asExpression() ?: "1".asExpression(),
it.getAsJsonPrimitive("weight")?.asString?.asExpression() ?: "1".asExpression()
PokemonProperties.parse(it.get("pokemon").asString),
it.get("levelVariation")?.asString?.asExpression() ?: "0".asExpression(),
it.get("level")?.asString?.asExpression(),
it.get("npcLevels")?.asString?.split("-")?.let { it[0].toInt()..it[1].toInt() } ?: 1..100,
it.get("selectableTimes")?.asString?.asExpression() ?: "1".asExpression(),
it.get("weight")?.asString?.asExpression() ?: "1".asExpression()
)
}.toMutableList()
isStatic = json.getAsJsonPrimitive("isStatic").asBoolean
isStatic = json.get("isStatic").asBoolean
json.get("useFixedRandom")?.asBoolean?.let { useFixedRandom = it }
}
class DynamicPokemon(
val pokemon: PokemonProperties,
val levelVariation: Expression,
val level: Expression? = null,
val npcLevels: IntRange,
val selectableTimes: Expression,
val weight: Expression = "1".asExpression()
@@ -99,6 +105,7 @@ class PoolPartyProvider : NPCPartyProvider {
fun formulateParty(npc: NPCEntity, level: Int, players: List<ServerPlayer>, party: NPCPartyStore) {
val runtime = MoLangRuntime().setup().withQueryValue("npc", npc.struct)
val random = if (useFixedRandom) Random(npc.uuid.hashCode()) else Random.Default
runtime.withQueryValue("level", DoubleValue(level))
runtime.withQueryValue("players", players.asArrayValue { it.asMoLangValue() })
if (players.size == 1) {
@@ -107,14 +114,14 @@ class PoolPartyProvider : NPCPartyProvider {
}
val minPokemon = runtime.resolveInt(this.minPokemon)
val maxPokemon = runtime.resolveInt(this.maxPokemon)
var desiredPokemonCount = (minPokemon..maxPokemon).random()
var desiredPokemonCount = (minPokemon..maxPokemon).random(random)
val workingPool = pool.filter { level in it.npcLevels && runtime.resolveInt(it.selectableTimes) > 0 }.toMutableList()
val useCounts = mutableMapOf<DynamicPokemon, Int>()
while (desiredPokemonCount > 0 && workingPool.any { it.hasWeight(runtime) }) {
val selected = workingPool.filter { it.getWeight(runtime) == -1F }.randomOrNull()
?: workingPool.weightedSelection { it.getWeight(runtime) }
val selected = workingPool.filter { it.getWeight(runtime) == -1F }.randomOrNull(random)
?: workingPool.weightedSelection(random = random) { it.getWeight(runtime) }
?: break
useCounts[selected] = useCounts.getOrDefault(selected, 0) + 1
val allowedSelections = runtime.resolveInt(selected.selectableTimes)
@@ -124,9 +131,10 @@ class PoolPartyProvider : NPCPartyProvider {
desiredPokemonCount--
// If the Pokémon's props specifies a level then use that, otherwise choose a random level within the range
val levelVariation = (0..runtime.resolveInt(selected.levelVariation)).random()
val levelVariation = (0..runtime.resolveInt(selected.levelVariation)).random(random)
val randomLevel = level + levelVariation
val instance = selected.pokemon.copy().also { it.level = it.level ?: randomLevel }.create()
val dictatedLevel = selected.level?.let { runtime.resolveInt(it) }
val instance = selected.pokemon.copy().also { it.level = it.level ?: dictatedLevel ?: randomLevel }.create()
party.add(instance)
}
}
@@ -32,5 +32,5 @@ class WeightedNPCVariationProvider : NPCVariationProvider {
override val aspects: Set<String>
get() = options.flatMap(WeightedAspect::aspects).toSet()
override fun provideAspects(npcEntity: NPCEntity) = options.weightedSelection(WeightedAspect::weight)?.aspects ?: emptySet()
override fun provideAspects(npcEntity: NPCEntity) = options.weightedSelection { it.weight }?.aspects ?: emptySet()
}
@@ -82,6 +82,8 @@ object CobblemonPermissions {
val ABANDON_MULTITEAM = this.create("${COMMAND_PREFIX}abandonmultiteam", PermissionLevel.NONE)
val RUN_MOLANG_SCRIPT = this.create("${COMMAND_PREFIX}runmolangscript", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
fun all(): Iterable<Permission> = this.permissions
private fun create(node: String, level: PermissionLevel): Permission {
@@ -8,13 +8,13 @@
package com.cobblemon.mod.common.api.pokedex
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokedexFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.resources.ResourceLocation
abstract class AbstractPokedexManager {
@@ -23,11 +23,9 @@ abstract class AbstractPokedexManager {
private val globalCalculatedValues = mutableMapOf<GlobalPokedexValueCalculator<*>, Any>()
@Transient
val struct = QueryStruct(hashMapOf()).addStandardFunctions()
.addFunction("get_species_record") { params ->
val speciesId = params.getString(0).asIdentifierDefaultingNamespace()
speciesRecords[speciesId]?.struct ?: QueryStruct(hashMapOf())
}
val struct = ObjectValue<AbstractPokedexManager>(this)
.addStandardFunctions()
.addPokedexFunctions(this)
fun deleteSpeciesRecord(speciesId: ResourceLocation) {
speciesRecords.remove(speciesId)
@@ -11,6 +11,8 @@ package com.cobblemon.mod.common.api.pokedex
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.struct.VariableStruct
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.PokedexDataChangedEvent
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -19,6 +21,7 @@ import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeEnumConstant
import com.cobblemon.mod.common.util.writeString
import com.google.common.collect.Sets
import com.mojang.datafixers.util.Either
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
@@ -123,6 +126,10 @@ class FormDexRecord {
}
speciesDexRecord.addInformation(pokemon, knowledge)
speciesDexRecord.onFormRecordUpdated(this)
(speciesDexRecord.pokedexManager as? PokedexManager)?.let { pokedexManager ->
CobblemonEvents.POKEDEX_DATA_CHANGED.post(PokedexDataChangedEvent(Either.right(pokemon), knowledge, pokedexManager.uuid, this))
}
}
private fun addInformation(pokedexEntityData: PokedexEntityData, knowledge: PokedexEntryProgress) {
@@ -133,6 +140,10 @@ class FormDexRecord {
}
speciesDexRecord.addInformation(pokedexEntityData, knowledge)
speciesDexRecord.onFormRecordUpdated(this)
(speciesDexRecord.pokedexManager as? PokedexManager)?.let { pokedexManager ->
CobblemonEvents.POKEDEX_DATA_CHANGED.post(PokedexDataChangedEvent(Either.left(pokedexEntityData), knowledge, pokedexManager.uuid, this))
}
}
/** Returns whether the given [Pokemon] and [knowledge] would add new information to the Pokédex.*/
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -162,7 +163,7 @@ interface Evolution : EvolutionLike {
evolutionMethod(pokemon)
pokemon.getOwnerPlayer()?.sendSystemMessage(lang("ui.evolve.into", preEvoName, pokemon.species.translatedName))
} else {
pokemonEntity.busyLocks.add("evolving")
pokemonEntity.entityData.set(PokemonEntity.EVOLUTION_STARTED, true)
pokemonEntity.navigation.stop()
pokemonEntity.after(1F) {
evolutionAnimation(pokemonEntity)
@@ -172,7 +173,7 @@ interface Evolution : EvolutionLike {
}
pokemonEntity.after( seconds = 12F ) {
cryAnimation(pokemonEntity)
pokemonEntity.busyLocks.remove("evolving")
pokemonEntity.entityData.set(PokemonEntity.EVOLUTION_STARTED, false)
pokemon.getOwnerPlayer()?.sendSystemMessage(lang("ui.evolve.into", preEvoName, pokemon.species.translatedName))
}
}
@@ -12,6 +12,8 @@ import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.FishingSpawningContext
import com.cobblemon.mod.common.util.itemRegistry
import net.minecraft.world.item.Item
import net.minecraft.world.item.enchantment.EnchantmentHelper
import net.minecraft.world.item.enchantment.Enchantments
import net.minecraft.world.level.block.Block
/**
@@ -33,9 +35,43 @@ class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
return false
} else if (neededNearbyBlocks != null && neededNearbyBlocks!!.none { cond -> ctx.nearbyBlockTypes.any { cond.fits(it, ctx.blockRegistry) } }) {
return false
} else {
return true
}
if (minLureLevel != null) { // check for the lureLevel of the rod
val pokerodStack = ctx.rodStack
val lureLevel = EnchantmentHelper.getItemEnchantmentLevel(
ctx.enchantmentRegistry.getHolder(Enchantments.LURE).get(),
pokerodStack
)
if (lureLevel < minLureLevel!!) {
return false
} else if (maxLureLevel != null && lureLevel > maxLureLevel!!) {
return false
}
}
if (bait != null) { // check for the bait on the bobber
val pokerodBait = ctx.rodBait?.item
if (pokerodBait != bait) {
return false
}
}
if (rodType != null) { // check for the type of pokerod being used
val pokerodItem = ctx.rodItem
if (pokerodItem?.pokeRodId != rodType) {
return false
}
}
/*if (ctx is FishingSpawningContext && (ctx as FishingSpawningContext).rodItem != null) { // check if the bait attracts certain EV yields
val pokerodItem = (ctx as FishingSpawningContext).rodItem
// todo check if the EV yield of the berry matches the bait EV attract maybe?
if (// todo if bait EV yield != EV yield of pokemon consideration //Registries.ITEM.getId(pokerodItem?.bait?.item).path == )
return false
}*/
return true
}
companion object {
@@ -116,24 +116,6 @@ abstract class SpawningCondition<T : SpawningContext> {
}
) {
return false
} else if (minLureLevel != null && ctx is FishingSpawningContext) { // check for the lureLevel of the rod
val pokerodStack = (ctx as FishingSpawningContext).rodStack
val lureLevel = EnchantmentHelper.getItemEnchantmentLevel(ctx.enchantmentRegistry.getHolder(Enchantments.LURE).get(), pokerodStack)
if (lureLevel < minLureLevel!!) {
return false
} else if (maxLureLevel != null && lureLevel > maxLureLevel!!) {
return false
}
} else if (bait != null && ctx is FishingSpawningContext) { // check for the bait on the bobber
val pokerodBait = (ctx as FishingSpawningContext).rodBait?.item
if (pokerodBait != bait) {
return false
}
} else if (rodType != null && ctx is FishingSpawningContext) { // check for the type of pokerod being used
val pokerodItem = (ctx as FishingSpawningContext).rodItem
if (pokerodItem?.pokeRodId != rodType) {
return false
}
} else if (isSlimeChunk != null && isSlimeChunk != false) {
val isSlimeChunk = WorldgenRandom.seedSlimeChunk(ctx.position.x shr 4, ctx.position.z shr 4, ctx.world.seed, 987234911L).nextInt(10) == 0
@@ -152,15 +134,6 @@ abstract class SpawningCondition<T : SpawningContext> {
return random.nextInt(10) == 0*/
}
/*else if (ctx is FishingSpawningContext && (ctx as FishingSpawningContext).rodItem != null) { // check if the bait attracts certain EV yields
val pokerodItem = (ctx as FishingSpawningContext).rodItem
// todo check if the EV yield of the berry matches the bait EV attract maybe?
if (// todo if bait EV yield != EV yield of pokemon consideration //Registries.ITEM.getId(pokerodItem?.bait?.item).path == )
return false
}*/
return true
}
@@ -16,7 +16,6 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.feature.SeasonFeatureHandler
import com.cobblemon.mod.common.util.weightedSelection
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Player
/**
* A [SpawnAction] that will spawn a single [PokemonEntity].
@@ -33,6 +33,11 @@ open class PlayerLevelRangeInfluence(
val noPokemonRange: IntRange = 1 .. config.minimumLevelRangeMax,
val recalculationMillis: Long = 5000L
) : SpawningInfluence {
companion object {
/** The internally tuned variation for player level range influences */
val TYPICAL_VARIATION = 5
}
val uuid = player.uuid
var lastCalculatedTime: Long = 0
var previousRange: IntRange = noPokemonRange
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
import com.cobblemon.mod.common.api.spawning.SpawnerManager
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence.Companion.TYPICAL_VARIATION
import com.cobblemon.mod.common.api.spawning.influence.RestrictedSpawnBlocksInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
@@ -42,7 +43,7 @@ object PlayerSpawnerFactory {
var influenceBuilders = mutableListOf<(player: ServerPlayer) -> SpawningInfluence?>({
PlayerLevelRangeInfluence(
it,
variation = 5
variation = TYPICAL_VARIATION
)
}, { RestrictedSpawnBlocksInfluence() })
@@ -30,8 +30,9 @@ abstract class TriggerSpawner<T : SpawnCause>(override val name: String, var spa
private var selector: SpawningSelector = FlatContextWeightedSelector()
override val influences = mutableListOf<SpawningInfluence>()
open fun run(cause: T, world: ServerLevel, pos: BlockPos): CompletableFuture<*>? {
open fun run(cause: T, world: ServerLevel, pos: BlockPos, influences: List<SpawningInfluence> = emptyList()): CompletableFuture<*>? {
val context = parseContext(cause, world, pos) ?: return null
context.influences.addAll(influences)
selector.select(this, listOf(context))?.let { (_, spawn) ->
val action = spawn.doSpawn(context)
action.complete()
@@ -269,7 +269,7 @@ open class PartyStore(override val uuid: UUID) : PokemonStore<PartyPosition>() {
BattlePokemon.playerOwned(it)
}.also { if (healPokemon) it.effectedPokemon.heal() }
}.toMutableList()
if(leadingPokemon != null) {
if (leadingPokemon != null) {
Collections.rotate(result, result.size - this.indexOfFirst { it.uuid == leadingPokemon })
}
return result
@@ -102,20 +102,32 @@ open class PlayerPartyStore(
for (pokemon in this) {
// Awake from fainted
if (pokemon.isFainted()) {
pokemon.faintedTimer -= 1
if (pokemon.faintedTimer <= -1) {
val php = ceil(pokemon.maxHealth * Cobblemon.config.faintAwakenHealthPercent)
pokemon.currentHealth = php.toInt()
player.sendSystemMessage(Component.translatable("cobblemon.party.faintRecover", pokemon.getDisplayName()))
//Skip awaken logic check if config value is 0
if (Cobblemon.config.faintAwakenHealthPercent > 0) {
pokemon.faintedTimer -= 1
if (pokemon.faintedTimer <= -1) {
val php = ceil(pokemon.maxHealth * Cobblemon.config.faintAwakenHealthPercent)
pokemon.currentHealth = php.toInt()
player.sendSystemMessage(
Component.translatable(
"cobblemon.party.faintRecover",
pokemon.getDisplayName()
)
)
}
}
}
// Passive healing while less than full health
else if (pokemon.currentHealth < pokemon.maxHealth) {
pokemon.healTimer--
if (pokemon.healTimer <= -1) {
pokemon.healTimer = Cobblemon.config.healTimer
val healAmount = 1.0.coerceAtLeast(pokemon.maxHealth.toDouble() * Cobblemon.config.healPercent)
pokemon.currentHealth = pokemon.currentHealth + round(healAmount).toInt()
//Skip passive healing logic check if config value is 0
if (Cobblemon.config.healPercent > 0) {
pokemon.healTimer--
if (pokemon.healTimer <= -1) {
pokemon.healTimer = Cobblemon.config.healTimer
val healAmount =
1.0.coerceAtLeast(pokemon.maxHealth.toDouble() * Cobblemon.config.healPercent)
pokemon.currentHealth = pokemon.currentHealth + round(healAmount).toInt()
}
}
}
@@ -204,4 +216,4 @@ open class PlayerPartyStore(
super.set(position, pokemon)
pokemon.getOwnerPlayer()?.let { CobblemonCriteria.PARTY_CHECK.trigger(it, this) }
}
}
}
@@ -100,6 +100,10 @@ object BattleBuilder {
)
}
if (actor.pokemonList.any { it.entity?.isBusy == true }) {
errors.participantErrors[actor] += BattleStartError.targetIsBusy(player.displayName ?: player.name)
}
if (BattleRegistry.getBattleByParticipatingPlayer(player) != null) {
errors.participantErrors[actor] += BattleStartError.alreadyInBattle(player)
}
@@ -109,16 +113,13 @@ object BattleBuilder {
player2Actor.battleTheme = player1.getBattleTheme()
return if (errors.isEmpty) {
var result: BattleStartResult = errors
BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(player1Actor),
side2 = BattleSide(player2Actor)
).ifSuccessful {
it.battlePartyStores.addAll(battlePartyStores)
result = SuccessfulBattleStart(it)
}
result
} else {
errors
}
@@ -178,6 +179,10 @@ object BattleBuilder {
)
}
if (actor.pokemonList.any { it.entity?.isBusy == true }) {
errors.participantErrors[actor] += BattleStartError.targetIsBusy(player.displayName ?: player.name)
}
if (BattleRegistry.getBattleByParticipatingPlayer(player) != null) {
errors.participantErrors[actor] += BattleStartError.alreadyInBattle(player)
}
@@ -206,13 +211,12 @@ object BattleBuilder {
return if (errors.isEmpty) {
BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(playerActors[0], playerActors[1]),
side2 = BattleSide(playerActors[2], playerActors[3])
battleFormat = battleFormat,
side1 = BattleSide(playerActors[0], playerActors[1]),
side2 = BattleSide(playerActors[2], playerActors[3])
).ifSuccessful {
it.battlePartyStores.addAll(battlePartyStores)
}
errors
} else {
errors
}
@@ -248,7 +252,7 @@ object BattleBuilder {
val wildActor = PokemonBattleActor(pokemonEntity.pokemon.uuid, BattlePokemon(pokemonEntity.pokemon), fleeDistance)
val errors = ErroredBattleStart()
if(playerTeam.isNotEmpty() && playerTeam[0].health <= 0){
if (playerTeam.isNotEmpty() && playerTeam[0].health <= 0){
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
actorEntity = player,
requiredCount = battleFormat.battleType.slotsPerActor,
@@ -264,6 +268,10 @@ object BattleBuilder {
)
}
if (playerActor.pokemonList.any { it.entity?.isBusy == true }) {
errors.participantErrors[playerActor] += BattleStartError.targetIsBusy(player.displayName ?: player.name)
}
if (BattleRegistry.getBattleByParticipatingPlayer(player) != null) {
errors.participantErrors[playerActor] += BattleStartError.alreadyInBattle(playerActor)
}
@@ -275,7 +283,6 @@ object BattleBuilder {
playerActor.battleTheme = pokemonEntity.getBattleTheme()
return if (errors.isEmpty) {
var result: BattleStartResult = errors
BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(playerActor),
@@ -284,9 +291,7 @@ object BattleBuilder {
if (!cloneParties) {
pokemonEntity.battleId = it.battleId
}
result = SuccessfulBattleStart(it)
}
result
} else {
errors
}
@@ -348,19 +353,20 @@ object BattleBuilder {
)
}
if (playerActor.pokemonList.any { it.entity?.isBusy == true }) {
errors.participantErrors[playerActor] += BattleStartError.targetIsBusy(player.displayName ?: player.name)
}
playerActor.battleTheme = npcEntity.getBattleTheme()
return if (errors.isEmpty) {
var result: BattleStartResult = errors
BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(playerActor),
side2 = BattleSide(npcActor)
).ifSuccessful { battle ->
npcEntity.entityData.update(NPCEntity.BATTLE_IDS) { it + battle.battleId }
result = SuccessfulBattleStart(battle)
}
result
} else {
errors
}
@@ -394,7 +400,7 @@ interface BattleStartError {
fun alreadyInBattle(pokemonEntity: PokemonEntity) = AlreadyInBattleError(pokemonEntity.uuid, pokemonEntity.effectiveName())
fun alreadyInBattle(actor: BattleActor) = AlreadyInBattleError(actor.uuid, actor.getName())
fun noParty(npcEntity: NPCEntity) = NoPartyError(npcEntity)
fun targetIsBusy(targetName: MutableComponent) = BusyError(targetName)
fun targetIsBusy(targetName: Component) = BusyError(targetName)
fun insufficientPokemon(
actorEntity: Entity,
requiredCount: Int,
@@ -474,7 +480,7 @@ class AlreadyInBattleError(
}
}
class BusyError(
val targetName: MutableComponent
val targetName: Component
): BattleStartError {
override fun getMessageFor(entity: Entity) = battleLang("errors.busy", targetName)
}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.battles
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.battles.BattleStartedPostEvent
@@ -178,19 +179,35 @@ object BattleRegistry {
ShowdownService.service.startBattle(battle, messages.toTypedArray())
}
/**
* Instantiates a new [PokemonBattle] and launches the Showdown service.
*
* @param battleFormat The format to use for the battle.
* @param side1 The first side for the battle.
* @param side2 The second side for the battle.
* @param canPreempt Whether the battle can be blocked by subscribers to [CobblemonEvents.BATTLE_STARTED_PRE].
*
* NOTE: this does NOT validate the [battleFormat] or sides before launching Showdown.
* This creates the battle and hands it off to Showdown - YOU WILL GET ISSUES IF THE BATTLE IS INVALID!
* See [BattleBuilder] functions for how the various types of battles are built and validated.
*/
fun startBattle(
battleFormat: BattleFormat,
side1: BattleSide,
side2: BattleSide,
silent: Boolean = false
canPreempt: Boolean = true
): BattleStartResult {
val battle = PokemonBattle(battleFormat, side1, side2)
if (silent) return SuccessfulBattleStart(battle)
val start: () -> Unit = {
battleMap[battle.battleId] = battle
startShowdown(battle)
}
if (!canPreempt) start().also { return SuccessfulBattleStart(battle) }
val preBattleEvent = BattleStartedPreEvent(battle)
CobblemonEvents.BATTLE_STARTED_PRE.postThen(preBattleEvent) {
battleMap[battle.battleId] = battle
startShowdown(battle)
start()
CobblemonEvents.BATTLE_STARTED_POST.post(BattleStartedPostEvent(battle))
return SuccessfulBattleStart(battle)
}
@@ -69,7 +69,7 @@ object ShowdownInterpreter {
updateInstructionParser["-copyboost"] = { _, _, message, _ -> CopyBoostInstruction(message) }
updateInstructionParser["-crit"] = { _, instructionSet, message, _ -> CritInstruction(message, instructionSet) }
updateInstructionParser["-curestatus"] = { _, _, message, _ -> CureStatusInstruction(message) }
updateInstructionParser["detailschange"] = { _, _, message, _ -> DetailsChangeInstruction(message) }
updateInstructionParser["detailschange"] = { _, _, message, _ -> FormeChangeInstruction(message) }
updateInstructionParser["-endability"] = { _, _, message, _ -> EndAbilityInstruction(message) }
updateInstructionParser["-end"] = { _, _, message, _ -> EndInstruction(message) }
updateInstructionParser["-enditem"] = { _, _, message, _ -> EndItemInstruction(message) }
@@ -78,6 +78,7 @@ object ShowdownInterpreter {
updateInstructionParser["-fieldactivate"] = { _, _, message, _ -> FieldActivateInstruction(message) }
updateInstructionParser["-fieldend"] = { _, _, message, _ -> FieldEndInstruction(message) }
updateInstructionParser["-fieldstart"] = { _, _, message, _ -> FieldStartInstruction(message) }
updateInstructionParser["-formechange"] = { _, _, message, _ -> FormeChangeInstruction(message) }
updateInstructionParser["-hitcount"] = { _, _, message, _ -> HitCountInstruction(message) }
updateInstructionParser["-immune"] = { _, _, message, _ -> ImmuneInstruction(message) }
updateInstructionParser["-invertboost"] = { _, _, message, _ -> InvertBoostInstruction(message) }
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.battles.interpreter.instructions
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
import com.cobblemon.mod.common.util.battleLang
/**
* Format: |detailschange|POKEMON|DETAILS|HP STATUS
*
* POKEMON has changed formes permanently (i.e. Mega Evolution) to DETAILS.
* @author Segfault Guy
* @since September 10th, 2023
*/
class DetailsChangeInstruction(val message: BattleMessage): InterpreterInstruction {
override fun invoke(battle: PokemonBattle) {
val battlePokemon = message.battlePokemon(0, battle) ?: return
val formName = message.argumentAt(1)?.split(',')?.get(0)?.substringAfter('-')?.lowercase() ?: return
battle.dispatchWaiting {
val pokemonName = battlePokemon.getName()
battle.broadcastChatMessage(battleLang("detailschange.$formName", pokemonName))
battle.majorBattleActions[battlePokemon.uuid] = message
}
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.battles.interpreter.instructions
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.battles.ShowdownInterpreter
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
import com.cobblemon.mod.common.util.battleLang
/**
* Format: |-formechange|POKEMON|SPECIES|HP STATUS or |detailschange|POKEMON|DETAILS|HP STATUS
*
* POKEMON has temporarily (-formechange) or permanently (detailschange) changed form to SPECIES/DETAILS.
* @author Segfault Guy
* @since December 9th, 2024
*/
class FormeChangeInstruction(val message: BattleMessage): InterpreterInstruction {
override fun invoke(battle: PokemonBattle) {
val battlePokemon = message.battlePokemon(0, battle) ?: return
val details = message.argumentAt(1)?.split(',')?.get(0)?.lowercase() ?: return
val speciesName = details.substringBefore('-')
val formName = details.substringAfterLast('-').ifBlank { speciesName }
val typeKey = if (message.id == "detailschange") "permanent" else "temporary"
ShowdownInterpreter.broadcastOptionalAbility(battle, message.effect(), battlePokemon)
battle.dispatchWaiting {
battle.minorBattleActions[battlePokemon.uuid] = message
val pokemonName = battlePokemon.getName()
val lang = when(formName) {
"busted", "hero", "complete" -> return@dispatchWaiting
"school", "wishiwashi", "meteor", "minior" -> battleLang("formechange.$formName", pokemonName)
speciesName -> battleLang("formechange.default.temporary.end", pokemonName)
else -> battleLang("formechange.default.$typeKey", pokemonName, formName)
}
battle.broadcastChatMessage(lang)
}
}
}
@@ -55,7 +55,6 @@ class PCBlock(properties: Properties): BaseEntityBlock(properties), SimpleWaterl
val CODEC = simpleCodec(::PCBlock)
val PART = EnumProperty.create("part", PCPart::class.java)
val ON = BooleanProperty.create("on")
val WATERLOGGED = BooleanProperty.create("waterlogged")
val NATURAL = BooleanProperty.create("natural")
private val NORTH_AABB_TOP = Shapes.or(
@@ -235,7 +234,7 @@ class PCBlock(properties: Properties): BaseEntityBlock(properties), SimpleWaterl
@Deprecated("Deprecated in Java")
override fun isPathfindable(
blockState: BlockState?,
blockState: BlockState,
pathComputationType: PathComputationType
): Boolean = false
@@ -157,7 +157,7 @@ class GildedChestBlock(settings: Properties, val type: Type = Type.RED) : BaseEn
// The yaw based on the block's facing direction
val yaw = facingToYaw[state.getValue(HorizontalDirectionalBlock.FACING)] ?: 0.0F
entity.entityData.set(PokemonEntity.SPAWN_DIRECTION, facingToYaw[state.getValue(HorizontalDirectionalBlock.FACING)])
entity.entityData.set(PokemonEntity.SPAWN_DIRECTION, yaw)
val offsetDir = state.getValue(HorizontalDirectionalBlock.FACING)
val vec = pos.toVec3d().add(offsetDir.stepX * 0.1 + 0.5, 0.0, offsetDir.stepZ * 0.1 + 0.5)
entity.moveTo(vec.x, vec.y, vec.z, yaw, entity.xRot)
@@ -17,9 +17,9 @@ import net.minecraft.world.item.alchemy.Potions
object BrewingRecipes {
val recipes: List<Triple<CobblemonIngredient, CobblemonIngredient, Item>> by lazy {
val recipes: List<Triple<CobblemonIngredient, Item, Item>> by lazy {
listOf(
Triple(CobblemonPotionIngredient(Potions.WATER), CobblemonItemIngredient(CobblemonItems.MEDICINAL_LEEK), CobblemonItems.MEDICINAL_BREW),
Triple(CobblemonPotionIngredient(Potions.WATER), CobblemonItems.MEDICINAL_LEEK, CobblemonItems.MEDICINAL_BREW),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.LEPPA_BERRY, CobblemonItems.ETHER),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.HOPO_BERRY, CobblemonItems.ELIXIR),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.ORAN_BERRY, CobblemonItems.POTION),
@@ -50,8 +50,8 @@ object BrewingRecipes {
)
}
private fun convert(input: Item, ingredient: Item, output: Item): Triple<CobblemonIngredient, CobblemonIngredient, Item> {
return Triple(CobblemonItemIngredient(input), CobblemonItemIngredient(ingredient), output)
private fun convert(input: Item, ingredient: Item, output: Item): Triple<CobblemonIngredient, Item, Item> {
return Triple(CobblemonItemIngredient(input), ingredient, output)
}
}
@@ -125,6 +125,7 @@ object ClientMoLangFunctions {
val maxPitch = params.getDoubleOrNull(3) ?: 70F
val minPitch = params.getDoubleOrNull(4) ?: -45F
val maxYaw = params.getDoubleOrNull(5) ?: 45F
val minYaw = params.getDoubleOrNull(6) ?: -45F
ObjectValue(
SingleBoneLookAnimation(
bone = model.getPart(boneName),
@@ -132,7 +133,8 @@ object ClientMoLangFunctions {
yawMultiplier = yawMultiplier.toFloat(),
maxPitch = maxPitch.toFloat(),
minPitch = minPitch.toFloat(),
maxYaw = maxYaw.toFloat()
maxYaw = maxYaw.toFloat(),
minYaw = minYaw.toFloat()
)
)
}
@@ -0,0 +1,13 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui
import net.minecraft.client.gui.components.Renderable
interface CobblemonRenderable : Renderable
@@ -18,7 +18,7 @@ import net.minecraft.network.chat.Component
class ExitButton(
pX: Int, pY: Int,
onPress: OnPress
): Button(pX, pY, WIDTH.toInt(), HEIGHT.toInt(), Component.literal("Exit"), onPress, DEFAULT_NARRATION) {
): Button(pX, pY, WIDTH.toInt(), HEIGHT.toInt(), Component.literal("Exit"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 26F
@@ -31,7 +31,7 @@ abstract class ScrollingWidget<T : ObjectSelectionList.Entry<T>>(
height, // Height
top, // Top
slotHeight // Slot Height
) {
), CobblemonRenderable {
override fun renderListBackground(guiGraphics: GuiGraphics) {}
override fun renderSelection(context: GuiGraphics, y: Int, entryWidth: Int, entryHeight: Int, borderColor: Int, fillColor: Int) {}
override fun renderDecorations(context: GuiGraphics, mouseX: Int, mouseY: Int) {}
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.battles.ShowdownActionResponse
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.ClientBattleActor
import com.cobblemon.mod.common.client.battle.SingleActionRequest
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleActionSelection
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleBackButton
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleGeneralActionSelection
@@ -29,7 +30,7 @@ import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen
class BattleGUI : Screen(battleLang("gui.title")) {
class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
companion object {
const val OPTION_VERTICAL_SPACING = 3
const val OPTION_HORIZONTAL_SPACING = 3
@@ -183,15 +184,16 @@ class BattleGUI : Screen(battleLang("gui.title")) {
override fun charTyped(chr: Char, modifiers: Int): Boolean {
if (chr.toString().equals(PartySendBinding.boundKey().displayName.string, ignoreCase = true) && CobblemonClient.battleOverlay.opacity == BattleOverlay.MAX_OPACITY && PartySendBinding.canAction()) {
val battle = CobblemonClient.battle ?: return false
battle.minimised = !battle.minimised
PartySendBinding.actioned()
return true
return minimizeBattle()
}
return super.charTyped(chr, modifiers)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (button == PartySendBinding.boundKey().value && CobblemonClient.battleOverlay.opacity == BattleOverlay.MAX_OPACITY && PartySendBinding.canAction()) {
return minimizeBattle()
}
val battle = CobblemonClient.battle
if (battle?.spectating == true && specBackButton.isHovered(mouseX, mouseY)) {
RemoveSpectatorPacket(battle.battleId).sendToServer()
@@ -199,4 +201,11 @@ class BattleGUI : Screen(battleLang("gui.title")) {
}
return super.mouseClicked(mouseX, mouseY, button)
}
private fun minimizeBattle(): Boolean {
val battle = CobblemonClient.battle ?: return false
battle.minimised = !battle.minimised
PartySendBinding.actioned()
return true
}
}
@@ -9,18 +9,19 @@
package com.cobblemon.mod.common.client.gui.battle.subscreen
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.gui.GuiGraphics
class BattleBackButton(val x: Float, val y: Float) {
class BattleBackButton(val x: Float, val y: Float) : CobblemonRenderable {
companion object {
const val WIDTH = 58
const val HEIGHT = 34
const val SCALE = 0.5F
}
fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
blitk(
matrixStack = context.pose(),
texture = cobblemonResource("textures/gui/battle/battle_back.png"),
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.battle.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.battle.ClientBattleMessageQueue
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.Minecraft
@@ -32,7 +33,7 @@ class BattleMessagePane(
FRAME_HEIGHT, // height
1, // top
LINE_HEIGHT
) {
), CobblemonRenderable {
var opacity = 1F
private var scrolling = false
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.battle.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.render.drawScaledText
import net.minecraft.client.gui.GuiGraphics
@@ -28,7 +29,7 @@ class BattleOptionTile(
val resource: ResourceLocation,
val text: MutableComponent,
val onClick: () -> Unit
) : Renderable, GuiEventListener, NarratableEntry {
) : CobblemonRenderable, GuiEventListener, NarratableEntry {
companion object {
const val OPTION_WIDTH = 90
const val OPTION_HEIGHT = 26
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.dialogue.widgets.DialogueBox
import com.cobblemon.mod.common.client.gui.dialogue.widgets.DialoguePortraitWidget
import com.cobblemon.mod.common.client.gui.dialogue.widgets.DialogueNameWidget
@@ -36,7 +37,7 @@ import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.Screen
class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTranslated()) {
class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTranslated()), CobblemonRenderable {
val speakers = dialogueDTO.speakers?.mapNotNull { (key, value) ->
val name = value.name
when (val face = value.face) {
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.gui.dialogue.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
@@ -22,7 +23,7 @@ class DialogueNameWidget(
val width: Int,
val height: Int,
val text: MutableComponent?
) : Renderable, GuiEventListener {
) : CobblemonRenderable, GuiEventListener {
companion object {
val nameResource = cobblemonResource("textures/gui/dialogue/dialogue_name.png")
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.gui.dialogue.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.dialogue.DialogueScreen
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
@@ -22,7 +23,7 @@ class DialoguePortraitWidget(
val y: Int,
val width: Int,
val height: Int
) : Renderable, GuiEventListener {
) : CobblemonRenderable, GuiEventListener {
companion object {
val DIALOGUE_ARROW_HEIGHT = 11
val DIALOGUE_ARROW_WIDTH = 6
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.dialogue.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.gui.drawCenteredText
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.dialogue.DialogueScreen
import com.cobblemon.mod.common.net.messages.client.dialogue.dto.DialogueInputDTO
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
@@ -36,7 +37,7 @@ class DialogueTextInputWidget(
width,
height,
"gui_dialogue_text_input".text()
) {
), CobblemonRenderable {
init {
setMaxLength(maxLength)
isFocused = true
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.dialogue.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.dialogue.DialogueScreen
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
@@ -22,7 +23,7 @@ class DialogueTimerWidget(
val y: Int,
val width: Int,
val height: Int,
) : Renderable, GuiEventListener {
) : CobblemonRenderable, GuiEventListener {
companion object {
val timerResource = cobblemonResource("textures/gui/dialogue/dialogue_timer_bar.png")
}
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.battle.ClientBattleChallenge
import com.cobblemon.mod.common.client.battle.ClientTeamRequest
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.server.*
@@ -35,7 +36,7 @@ class BattleConfigureGUI(
private val packet: PlayerInteractOptionsPacket,
private val activeRequest: ClientBattleChallenge? = null,
private val activeTeamRequest: ClientTeamRequest? = null
) : Screen(lang("ui.challenge.challenge_title")) {
) : Screen(lang("ui.challenge.challenge_title")), CobblemonRenderable {
companion object {
const val SIZE = 113
private val backgroundResource = cobblemonResource("textures/gui/interact/request/battle_request.png")
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.interact.battleRequest
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
@@ -25,7 +26,7 @@ class BattleRequestNavigationButton(
private val forwardIcon: ResourceLocation = forwardButtonResource,
private val backwardIcon: ResourceLocation = backwardsButtonResource,
onPress: OnPress
): Button(pX.toInt(), pY.toInt(), (WIDTH * SCALE).toInt(), (clickHeight * SCALE).toInt(), Component.literal("Navigation"), onPress, DEFAULT_NARRATION) {
): Button(pX.toInt(), pY.toInt(), (WIDTH * SCALE).toInt(), (clickHeight * SCALE).toInt(), Component.literal("Navigation"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
const val HEIGHT = 16
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.interact.battleRequest
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
@@ -21,7 +22,7 @@ class BattleResponseButton(
pX: Int, pY: Int,
private val accept: Boolean,
onPress: OnPress
): Button(pX, pY, (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Component.literal("Navigation"), onPress, DEFAULT_NARRATION) {
): Button(pX, pY, (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Component.literal("Navigation"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 34F
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
@@ -24,7 +25,7 @@ class BattleRequestButton(
pX: Int, pY: Int,
var text: MutableComponent,
onPress: OnPress
): Button(pX, pY, (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), text, onPress, DEFAULT_NARRATION) {
): Button(pX, pY, (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), text, onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 69F
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.callback.MoveSelectDTO
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.ExitButton
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
@@ -35,7 +36,7 @@ class MoveSelectConfiguration(
class MoveSelectGUI(
val config: MoveSelectConfiguration
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")) {
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable {
companion object {
const val WIDTH = 122
const val HEIGHT = 133
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.text.gold
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.MoveCategoryIcon
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.render.drawScaledText
@@ -35,7 +36,7 @@ class MoveSlotButton(
val ppMax: Int,
val enabled: Boolean = true,
onPress: OnPress
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Move"), onPress, CreateNarration { "".text() }) {
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Move"), onPress, CreateNarration { "".text() }), CobblemonRenderable {
companion object {
private val moveResource = cobblemonResource("textures/gui/summary/summary_move.png")
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.callback.PartySelectPokemonDTO
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.ExitButton
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
@@ -37,7 +38,7 @@ class PartySelectConfiguration(
)
class PartySelectGUI(
val config: PartySelectConfiguration
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")) {
) : Screen(Component.translatable("cobblemon.ui.interact.moveselect")), CobblemonRenderable {
companion object {
const val WIDTH = 163
const val HEIGHT = 132
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.summary.widgets.PartySlotWidget
import com.cobblemon.mod.common.client.render.drawScaledText
@@ -42,7 +43,7 @@ class PartySlotButton(
val enabled: Boolean = true,
val parent: PartySelectGUI,
onPress: OnPress
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Pokemon"), onPress, CreateNarration { "".text() }) {
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Pokemon"), onPress, CreateNarration { "".text() }), CobblemonRenderable {
companion object {
private val slotResource = cobblemonResource("textures/gui/interact/party_select_slot.png")
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.gui.interact.wheel
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
@@ -29,7 +30,7 @@ class InteractWheelButton(
private val colour: () -> Vector3f?,
onPress: OnPress,
private val canHover: (Double, Double) -> Boolean
) : Button(x, y, BUTTON_SIZE, BUTTON_SIZE, Component.literal("Interact"), onPress, DEFAULT_NARRATION) {
) : Button(x, y, BUTTON_SIZE, BUTTON_SIZE, Component.literal("Interact"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
const val BUTTON_SIZE = 69
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.gui.interact.wheel
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.startselection.widgets.preview.ArrowButton
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.common.collect.Multimap
@@ -20,7 +21,7 @@ import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import kotlin.math.max
class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelOption>, title: Component) : Screen(title) {
class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelOption>, title: Component) : Screen(title), CobblemonRenderable {
companion object {
const val SIZE = 140
const val OPTION_SIZE = 71
@@ -0,0 +1,109 @@
/*
* 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.npc
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.client.sounds.SoundManager
import net.minecraft.network.chat.MutableComponent
class NPCEditorButton(
var buttonX: Float,
var buttonY: Float,
var label: MutableComponent,
var cycleButtonState: Boolean? = null,
var buttonWidth: Int = Minecraft.getInstance().font.width(label) + (BUTTON_PADDING * 2),
val silent: Boolean = false,
val alignRight: Boolean = false,
val clickAction: OnPress
): Button(if (alignRight) (buttonX - buttonWidth).toInt() else buttonX.toInt(), buttonY.toInt(), buttonWidth, HEIGHT, "".text(), clickAction, DEFAULT_NARRATION) {
companion object {
val HEIGHT = 16
val BORDER_WIDTH = 2
val BUTTON_PADDING = 6
val buttonResource = cobblemonResource("textures/gui/npc/button_base.png")
val buttonBorderResource = cobblemonResource("textures/gui/npc/button_border.png")
}
var isWidgetActive = false
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
val matrices = context.pose()
// Left border
blitk(
matrixStack = matrices,
texture = buttonBorderResource,
x = x,
y = y,
width = BORDER_WIDTH,
height = HEIGHT,
vOffset = if (isMouseOver(mouseX.toDouble(), mouseY.toDouble()) || isWidgetActive) HEIGHT else 0,
textureWidth = 3,
textureHeight = HEIGHT * 2,
)
// Base
blitk(
matrixStack = matrices,
texture = buttonResource,
x = x + BORDER_WIDTH,
y = y,
width = buttonWidth - (BORDER_WIDTH * 2),
height = HEIGHT,
vOffset = if (isMouseOver(mouseX.toDouble(), mouseY.toDouble()) || isWidgetActive) HEIGHT else 0,
textureHeight = HEIGHT * 2,
)
// Right border
blitk(
matrixStack = matrices,
texture = buttonBorderResource,
x = x + (buttonWidth - BORDER_WIDTH),
y = y,
width = BORDER_WIDTH,
height = HEIGHT,
uOffset = 1,
vOffset = if (isMouseOver(mouseX.toDouble(), mouseY.toDouble()) || isWidgetActive) HEIGHT else 0,
textureWidth = 3,
textureHeight = HEIGHT * 2,
)
var buttonLabel = if (cycleButtonState != null) "options.${if (cycleButtonState as Boolean) "on" else "off"}.composed".asTranslated(label) else label
drawScaledText(
context = context,
text = buttonLabel,
x = x + (buttonWidth / 2),
y = y + 4,
centered = true,
shadow = true
)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (active && isMouseOver(mouseX, mouseY)) {
super.mouseClicked(mouseX, mouseY, button)
}
return false
}
override fun playDownSound(soundManager: SoundManager) {
if (active && !this.silent) {
soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
}
}
}
@@ -8,25 +8,36 @@
package com.cobblemon.mod.common.client.gui.npc
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.gui.drawText
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.npc.widgets.ConfigVariableList
import com.cobblemon.mod.common.client.gui.npc.widgets.NPCRenderWidget
import com.cobblemon.mod.common.client.gui.npc.widgets.NPCRenderWidget.Companion.HEIGHT
import com.cobblemon.mod.common.client.gui.npc.widgets.NPCRenderWidget.Companion.WIDTH
import com.cobblemon.mod.common.client.gui.npc.widgets.SimpleNPCTextInputWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
import com.cobblemon.mod.common.net.messages.client.npc.dto.NPCConfigurationDTO
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
import net.minecraft.client.gui.screens.Screen
import java.util.UUID
class NPCEditorScreen(
val npcId: Int,
val dto: NPCConfigurationDTO
) : Screen("gui.npc_editor.title".asTranslated()) {
) : Screen("gui.npc_editor.title".asTranslated()), CobblemonRenderable {
companion object {
const val BASE_WIDTH = 331
const val BASE_HEIGHT = 161
const val BASE_WIDTH = 360
const val BASE_HEIGHT = 220
val baseResource = cobblemonResource("textures/gui/npc/base.png")
}
val middleX: Int
@@ -41,53 +52,73 @@ class NPCEditorScreen(
override fun init() {
super.init()
addRenderableOnly(NPCRenderWidget(leftX + 6, topY + 22, dto.npcClass, dto.aspects))
addRenderableOnly(NPCRenderWidget(leftX + 12, topY + 35, dto.npcClass, dto.aspects))
addRenderableWidget(SimpleNPCTextInputWidget(
texture = cobblemonResource("textures/gui/npc/basic_text_input.png"),
getter = { dto.npcName.string },
setter = { dto.npcName = it.text() },
x = leftX + 6,
y = topY + 80,
width = 130,
height = 22
posX = leftX + 12,
posY = topY + 9,
width = 192,
height = 22,
maxLength = 32
))
addRenderableWidget(SimpleNPCTextInputWidget(
texture = cobblemonResource("textures/gui/npc/aspects_text_input.png"),
getter = { dto.aspects.joinToString() },
setter = {
dto.aspects.clear()
dto.aspects.addAll(it.split(",").map { it.trim() })
},
x = leftX + 6,
y = topY + 100,
width = 130,
posX = leftX + 12,
posY = topY + 155,
width = 116,
height = 40,
maxLength = 75,
maxLength = 72,
wrap = true
))
addRenderableWidget(
Button
.builder("Save".text()) {
SaveNPCPacket(npcId, dto).sendToServer()
this.minecraft!!.setScreen(null)
}
.pos(leftX + BASE_WIDTH - 42, topY + BASE_HEIGHT - 8)
.size(40, 16)
.build()
NPCEditorButton(
buttonX = leftX + 348F,
buttonY = topY + 201F,
label = lang("ui.generic.save"),
alignRight = true
) {
SaveNPCPacket(npcId, dto).sendToServer()
this.minecraft!!.setScreen(null)
}
)
addRenderableWidget(ConfigVariableList(leftX + 200, topY + 30, this))
addRenderableWidget(ConfigVariableList(leftX + 134, topY + 35, this))
}
override fun renderBlurredBackground(delta: Float) {}
override fun renderMenuBackground(context: GuiGraphics) {}
override fun isPauseScreen() = false
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
// blitk(
// matrixStack = context.pose(),
// texture = baseResource,
// x = leftX,
// y = topY,
// height = BASE_HEIGHT,
// width = BASE_WIDTH
// )
blitk(
matrixStack = context.pose(),
texture = baseResource,
x = leftX,
y = topY,
height = BASE_HEIGHT,
width = BASE_WIDTH
)
var extendedId = npcId.toString()
while (extendedId.length < 12) extendedId = "0$extendedId"
drawScaledTextJustifiedRight(
context = context,
text = extendedId.text(),
x = leftX + 348,
y = topY + 9,
shadow = true
)
super.render(context, mouseX, mouseY, delta)
}
}
@@ -8,16 +8,19 @@
package com.cobblemon.mod.common.client.gui.npc.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.npc.NPCClasses
import com.cobblemon.mod.common.api.npc.configuration.NPCConfigVariable
import com.cobblemon.mod.common.api.npc.configuration.NPCConfigVariable.NPCVariableType
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.npc.NPCEditorButton
import com.cobblemon.mod.common.client.gui.npc.NPCEditorScreen
import com.cobblemon.mod.common.client.gui.npc.widgets.ConfigVariableList.ConfigVariable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.ContainerObjectSelectionList
import net.minecraft.client.gui.components.CycleButton
import net.minecraft.client.gui.components.EditBox
import net.minecraft.client.gui.components.Tooltip
import net.minecraft.client.gui.components.events.GuiEventListener
@@ -25,7 +28,7 @@ import net.minecraft.client.gui.narration.NarratableEntry
class ConfigVariableList(
val listX: Int,
val listY: Int,
var listY: Int,
val parent: NPCEditorScreen
) : ContainerObjectSelectionList<ConfigVariable>(
Minecraft.getInstance(),
@@ -33,13 +36,15 @@ class ConfigVariableList(
HEIGHT, // height
0, // top
SLOT_HEIGHT + SLOT_SPACING
) {
), CobblemonRenderable {
companion object {
const val WIDTH = 200
const val HEIGHT = 120
const val SLOT_WIDTH = 160
const val WIDTH = 211
const val HEIGHT = 160
const val SLOT_WIDTH = 196
const val SLOT_HEIGHT = 33
const val SLOT_SPACING = 0
val textInputBackground = cobblemonResource("textures/gui/npc/text_input_base.png")
}
private var scrolling = false
@@ -47,15 +52,16 @@ class ConfigVariableList(
override fun getRowWidth() = SLOT_WIDTH
init {
listY += 4
this.x = listX
this.y = listY
correctSize()
setRenderHeader(false, 0)
val npcClass = NPCClasses.getByIdentifier(parent.dto.npcClass)
if (npcClass != null) {
npcClass.config.forEach { t ->
val value = parent.dto.variables[t.variableName] ?: t.defaultValue
addEntry(ConfigVariable(t, value, this))
npcClass.config.forEach { variable ->
val value = parent.dto.variables[variable.variableName] ?: variable.defaultValue
addEntry(ConfigVariable(variable, value, this))
}
}
}
@@ -65,20 +71,12 @@ class ConfigVariableList(
public override fun addEntry(entry: ConfigVariable) = super.addEntry(entry)
public override fun removeEntry(entry: ConfigVariable) = super.removeEntry(entry)
override fun renderListSeparators(guiGraphics: GuiGraphics) {}
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
correctSize()
super.renderWidget(context, mouseX, mouseY, partialTicks)
// Scroll Overlay
// blitk(
// matrixStack = context.pose(),
// texture = scrollOverlayResource,
// x = listX,
// y = listY - 13,
// height = 131,
// width = WIDTH
// )
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
@@ -114,7 +112,6 @@ class ConfigVariableList(
private fun correctSize() {
setRectangle(WIDTH, HEIGHT, listX, (listY - 4))
// setX(listX)
}
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
@@ -130,11 +127,12 @@ class ConfigVariableList(
val editBox = EditBox(
client.font,
parent.listX,
parent.listY + 4,
if (variable.type == NPCVariableType.NUMBER) SLOT_WIDTH - 100 else SLOT_WIDTH,
parent.listY + 8,
SLOT_WIDTH - 8,
SLOT_HEIGHT - 8,
variable.displayName,
).also {
it.isBordered = false
it.tooltip = Tooltip.create(variable.description)
it.height = SLOT_HEIGHT - 16
it.setMaxLength(250)
@@ -147,18 +145,23 @@ class ConfigVariableList(
it.setFilter { value -> value.toDoubleOrNull() != null || value.isBlank() || value == "." || value == "-" }
}
}
val cycleButton = CycleButton.onOffBuilder(booleanValue).create(variable.displayName) { _, value ->
booleanValue = value
parent.parent.dto.variables[variable.variableName] = if (value) "1" else "0"
val toggleButton = NPCEditorButton(
parent.listX.toFloat(),
parent.listY + 6F,
variable.displayName.copy(),
booleanValue,
SLOT_WIDTH
) {
booleanValue = !booleanValue
parent.parent.dto.variables[variable.variableName] = if (booleanValue) "1" else "0"
(it as NPCEditorButton).cycleButtonState = booleanValue
}.also {
it.height = SLOT_HEIGHT - 14
it.width = SLOT_WIDTH - 8
it.tooltip = Tooltip.create(variable.description)
}
init {
if (variable.type == NPCVariableType.BOOLEAN) {
children.add(cycleButton)
children.add(toggleButton) // children.add(cycleButton)
} else {
children.add(editBox)
}
@@ -188,42 +191,27 @@ class ConfigVariableList(
) {
val x = rowLeft - 4
val y = rowTop
val matrixStack = context.pose()
// blitk(
// matrixStack = matrixStack,
// texture = slotResource,
// x = x,
// y = y,
// height = SLOT_HEIGHT,
// width = rowWidth,
// vOffset = if (isHovered) SLOT_HEIGHT else 0,
// textureHeight = SLOT_HEIGHT * 2
// )
if (variable.type == NPCVariableType.BOOLEAN) {
cycleButton.x = x
cycleButton.y = y + 6
cycleButton.render(context, mouseX, mouseY, partialTicks)
toggleButton.x = x
toggleButton.y = y + 9
toggleButton.render(context, mouseX, mouseY, partialTicks)
} else {
drawScaledText(
context = context,
text = variable.displayName.visualOrderText,
x = x,
y = y + 4
y = y + 4,
shadow = true
)
editBox.x = x
editBox.y = y + 14
blitk(matrixStack = context.pose(), texture = textInputBackground, x = x, y = y + 16, height = 12, width = 1)
blitk(matrixStack = context.pose(), texture = textInputBackground, x = x + 1, y = y + 15, height = 14, width = SLOT_WIDTH - 2)
blitk(matrixStack = context.pose(), texture = textInputBackground, x = x + SLOT_WIDTH - 1, y = y + 16, height = 12, width = 1)
editBox.x = x + 4
editBox.y = y + 18
editBox.render(context, mouseX, mouseY, partialTicks)
}
}
// override fun mouseClicked(mouseX: Double, mouseY: Double, delta: Int): Boolean {
// if (moveButton.isHovered(mouseX, mouseY) && canUnpasture()) {
// moveButton.onPress()
// return true
// }
// return false
// }
}
}
@@ -8,11 +8,10 @@
package com.cobblemon.mod.common.client.gui.npc.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.gui.drawProfile
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.NPCModelRepository
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Renderable
import net.minecraft.client.gui.components.events.GuiEventListener
@@ -23,41 +22,40 @@ class NPCRenderWidget(
val y: Int,
var identifier: ResourceLocation,
val aspects: MutableSet<String>
) : Renderable, GuiEventListener {
) : CobblemonRenderable, GuiEventListener {
val state = FloatingState().also {
it.currentAspects = aspects
}
companion object {
val profileBackgroundResource = cobblemonResource("textures/gui/npc/profile_background.png")
const val WIDTH = 66
const val HEIGHT = 66
const val WIDTH = 116
const val HEIGHT = 112
}
override fun isFocused() = false
override fun setFocused(focused: Boolean) {}
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
blitk(
matrixStack = context.pose(),
texture = profileBackgroundResource,
x = x,
y = y,
width = WIDTH,
height = HEIGHT
)
context.enableScissor(
x,
y,
x + WIDTH,
y + HEIGHT
)
context.pose().pushPose()
context.pose().translate(x + WIDTH / 2F, y + HEIGHT / 2F, 0F)
// Decrease on Z-axis to prevent model from rendering above other components like tooltips
context.pose().translate(x + (WIDTH / 2F), y + HEIGHT + (HEIGHT / 4F), -500F)
drawProfile(
repository = NPCModelRepository,
resourceIdentifier = identifier,
matrixStack = context.pose(),
partialTicks = delta,
scale = 30F,
scale = 120F,
state = state
)
context.pose().popPose()
context.disableScissor()
}
}
@@ -9,89 +9,142 @@
package com.cobblemon.mod.common.client.gui.npc.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.gui.drawCenteredText
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import net.minecraft.Util
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.EditBox
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.contents.PlainTextContents.LiteralContents
import net.minecraft.client.gui.screens.Screen
import net.minecraft.client.renderer.RenderType
import net.minecraft.network.chat.Style
import net.minecraft.resources.ResourceLocation
import kotlin.math.floor
class SimpleNPCTextInputWidget(
getter: () -> String,
val texture: ResourceLocation,
val texture: ResourceLocation? = null,
private val setter: (String) -> Unit,
x: Int,
y: Int,
posX: Int,
posY: Int,
width: Int,
height: Int,
maxLength: Int = 100,
val shadow: Boolean = true,
val wrap: Boolean = false
) : EditBox(
Minecraft.getInstance().font,
x,
y,
posX + TEXT_PADDING,
posY,
width,
height,
"input".text()
) {
), CobblemonRenderable {
companion object {
const val TEXT_PADDING = 4
}
var focusedTime: Long = 0
init {
setMaxLength(maxLength)
isFocused = true
focusedTime = Util.getMillis()
value = getter()
this.setResponder { setter(it) }
setResponder { setter(it) }
setFocused(false)
isBordered = false
}
override fun setFocused(focused: Boolean) {
if (focused) focusedTime = Util.getMillis()
super.setFocused(focused)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
return if (mouseX.toInt() in x..(x + width) && mouseY.toInt() in y..(y + height)) {
isFocused = true
true
} else {
false
val clickedState = super.mouseClicked(mouseX, mouseY, button)
if (wrap) {
val splitLines = Minecraft.getInstance().font.splitter.splitLines(value, width - 8, Style.EMPTY)
val clickedLineIndex = floor((mouseY - y)/11).toInt()
if (clickedLineIndex >= 0 && splitLines.size > clickedLineIndex) {
val lineAtIndex = splitLines.get(clickedLineIndex)
var lineSubstring = ""
for (char in lineAtIndex.string) {
lineSubstring += char
val startToLineWidth = Minecraft.getInstance().font.width(lineSubstring.text())
if ((mouseX - x) <= startToLineWidth) break
}
var unwrappedLine = ""
splitLines.forEachIndexed { index, line ->
if (index == clickedLineIndex) {
unwrappedLine += lineSubstring
} else if (index < clickedLineIndex) {
unwrappedLine += line.string
}
}
this.moveCursorTo(maxOf(0, unwrappedLine.length - 1), Screen.hasShiftDown())
}
}
return clickedState
}
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
if (cursorPosition != value.length) {
moveCursorToEnd(false)
if (texture != null) {
blitk(
matrixStack = context.pose(),
x = x,
y = y,
width = width,
height = height,
texture = texture
)
}
blitk(
matrixStack = context.pose(),
x = x,
y = y,
width = width,
height = height,
texture = texture
)
context.pose().pushPose()
val scale = 0.8F
context.pose().scale(scale, scale, 1F)
if (wrap) {
val wrappedLines = Minecraft.getInstance().font.split(MutableComponent.create(LiteralContents(value)), ((width - 8) / scale).toInt())
val showCursor = isFocused && ((Util.getMillis() - this.focusedTime) / 300L % 2L == 0L)
val input = (if (isFocused) "${value}${if ((cursorPosition == value.length) && showCursor) "_" else ""}" else value)
var cursorLine = ""
var cursorLineIndex = -1
var cursorLinePos = 0
var accumlatedLength = 0
val wrappedLines = Minecraft.getInstance().font.splitter.splitLines(input, width - (TEXT_PADDING * 2), Style.EMPTY)
for ((index, line) in wrappedLines.withIndex()) {
context.drawString(
Minecraft.getInstance().font,
line,
((x + 4) / scale).toInt(),
((y + index * 10 + 5) / scale).toInt(),
0xFFFFFF,
false
accumlatedLength += line.string.length
if (cursorLineIndex < 0 && accumlatedLength > cursorPosition) {
cursorLineIndex = index
cursorLine = line.string
cursorLinePos = if (cursorLineIndex > 0) cursorPosition - (accumlatedLength - line.string.length) else cursorPosition
}
drawScaledText(
context = context,
text = line.string.text(),
x = x,
y = y + index * 10 + 1,
colour = 0xDDDDDD,
shadow = true
)
}
if (showCursor && !value.isEmpty() && cursorPosition != value.length) {
val startToCursorWidth = Minecraft.getInstance().font.width((cursorLine.substring(0, cursorLinePos).text()))
context.fill(
RenderType.guiTextHighlight(),
x + startToCursorWidth - 1,
y + cursorLineIndex * 10 + 1,
x + startToCursorWidth,
y + (cursorLineIndex * 10 + 1) + 9,
-3092272
)
}
} else {
drawCenteredText(
context = context,
text = value.text(),
x = (x + width / 2F) / scale,
y = (y + height / 2 - 4) / scale,
shadow = true,
colour = 0xFFFFFF
)
super.renderWidget(context, mouseX, mouseY, delta)
}
context.pose().popPose()
}
}
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pc.StorageSlot
import com.cobblemon.mod.common.client.gui.summary.widgets.PartySlotWidget
@@ -40,7 +41,7 @@ class PasturePokemonScrollList(
HEIGHT, // height
0, // top
SLOT_HEIGHT + SLOT_SPACING
) {
), CobblemonRenderable {
companion object {
const val WIDTH = 70
const val HEIGHT = 120
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.gui.pasture
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
@@ -18,7 +19,7 @@ import net.minecraft.network.chat.Component
class PastureSlotIconButton(
var xPos: Int, var yPos: Int,
onPress: OnPress
) : Button(xPos, yPos, (SIZE * SCALE).toInt(), (SIZE * SCALE).toInt(), Component.literal("Pasture Move"), onPress, DEFAULT_NARRATION) {
) : Button(xPos, yPos, (SIZE * SCALE).toInt(), (SIZE * SCALE).toInt(), Component.literal("Pasture Move"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
const val SIZE = 14
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.pasture
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
@@ -22,7 +23,7 @@ import net.minecraft.network.chat.Component
class RecallButton(
x: Int, y: Int,
onPress: OnPress
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Retrieve"), onPress, DEFAULT_NARRATION) {
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Retrieve"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 70
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.pc
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
@@ -21,7 +22,7 @@ class NavigationButton(
pX: Int, pY: Int,
private val forward: Boolean,
onPress: OnPress
): Button(pX, pY, (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Component.literal("Navigation"), onPress, DEFAULT_NARRATION) {
): Button(pX, pY, (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Component.literal("Navigation"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 8F
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.ExitButton
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.gui.summary.Summary
@@ -40,7 +41,7 @@ class PCGUI(
val pc: ClientPC,
val party: ClientParty,
val configuration: PCGUIConfiguration
) : Screen(Component.translatable("cobblemon.ui.pc.title")) {
) : Screen(Component.translatable("cobblemon.ui.pc.title")), CobblemonRenderable {
companion object {
const val BASE_WIDTH = 349
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.pc
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
@@ -23,7 +24,7 @@ class ReleaseButton(
x: Int, y: Int,
private val parent: StorageWidget,
onPress: OnPress
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Release"), onPress, DEFAULT_NARRATION) {
) : Button(x, y, WIDTH, HEIGHT, Component.literal("Release"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 58
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.pc
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
@@ -24,7 +25,7 @@ class ReleaseConfirmButton(
private val parent: StorageWidget,
private val subKey: String,
onPress: OnPress
) : Button(x, y, WIDTH, HEIGHT, Component.literal("ReleaseConfirm"), onPress, DEFAULT_NARRATION) {
) : Button(x, y, WIDTH, HEIGHT, Component.literal("ReleaseConfirm"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 30
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.gui.pc
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.pasture.PasturePCGUIConfiguration
import com.cobblemon.mod.common.client.render.drawScaledText
@@ -31,7 +32,7 @@ open class StorageSlot(
x: Int, y: Int,
private val parent: StorageWidget,
onPress: OnPress
) : Button(x, y, SIZE, SIZE, Component.literal("StorageSlot"), onPress, DEFAULT_NARRATION) {
) : Button(x, y, SIZE, SIZE, Component.literal("StorageSlot"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
val state = FloatingState()
companion object {
@@ -29,6 +29,7 @@ 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.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.HEADER_BAR_HEIGHT
@@ -75,7 +76,7 @@ class PokedexGUI private constructor(
val type: PokedexType,
val initSpecies: ResourceLocation?,
val blockPos: BlockPos?
): Screen(Component.translatable("cobblemon.ui.pokedex.title")) {
): Screen(Component.translatable("cobblemon.ui.pokedex.title")), CobblemonRenderable {
companion object {
private val screenBackground = cobblemonResource("textures/gui/pokedex/pokedex_screen.png")
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.pokedex
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
import net.minecraft.client.gui.narration.NarrationElementOutput
@@ -27,7 +28,7 @@ class ScaledButton(
val scale: Float = 0.5F,
val silent: Boolean = false,
val clickAction: Button.OnPress
): Button(buttonX.toInt(), buttonY.toInt(), buttonWidth.toInt(), buttonHeight.toInt(), "".text(), clickAction, DEFAULT_NARRATION) {
): Button(buttonX.toInt(), buttonY.toInt(), buttonWidth.toInt(), buttonHeight.toInt(), "".text(), clickAction, DEFAULT_NARRATION), CobblemonRenderable {
var isWidgetActive = false
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.font
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
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.SCALE
@@ -33,7 +34,7 @@ class SearchWidget(
height: Int,
text: Component = "Search".text(),
val update: () -> (Unit)
): EditBox(Minecraft.getInstance().font, posX.toInt(), posY.toInt(), width, height, text) {
): EditBox(Minecraft.getInstance().font, posX.toInt(), posY.toInt(), width, height, text), CobblemonRenderable {
companion object {
private val backgroundOverlay = cobblemonResource("textures/gui/pokedex/pokedex_screen_search_overlay.png")
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.pokenav
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.summary.Summary
import com.cobblemon.mod.common.client.keybind.boundKey
import com.cobblemon.mod.common.client.keybind.keybinds.PokeNavigatorBinding
@@ -28,7 +29,7 @@ import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
class PokeNav : Screen(Component.translatable("cobblemon.ui.pokenav.title")) {
class PokeNav : Screen(Component.translatable("cobblemon.ui.pokenav.title")), CobblemonRenderable {
companion object {
// Limiting
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.gui.ColourLibrary
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.asTranslated
import net.minecraft.client.gui.GuiGraphics
@@ -31,7 +32,7 @@ open class PokeNavImageButton(
private val text: MutableComponent,
private val canClick: () -> Boolean = { true }
// TODO: Make lang key per button
): Button(pX, pY, pWidth, pHeight, "cobblemon.ui.pokenav.narrator.backbutton".asTranslated(), onPress, DEFAULT_NARRATION) {
): Button(pX, pY, pWidth, pHeight, "cobblemon.ui.pokenav.narrator.backbutton".asTranslated(), onPress, DEFAULT_NARRATION), CobblemonRenderable {
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
// Render Button Image
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.gui.blitk
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.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.startselection.widgets.CategoryList
import com.cobblemon.mod.common.client.gui.startselection.widgets.ExitButton
import com.cobblemon.mod.common.client.gui.startselection.widgets.preview.ArrowButton
@@ -47,7 +48,7 @@ import net.minecraft.network.chat.Component
* @author Qu
* @since 2022-06-18
*/
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()) {
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()), CobblemonRenderable {
companion object {
// Size of UI at scale 1
@@ -132,7 +133,8 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
pX = x + 85, pY = y + 50,
pWidth = 102, pHeight = 100,
pokemon = this,
baseScale = 2.0f
baseScale = 2.0f,
playCryOnClick = true,
)
typeWidget = typeWidget(this, x, y)
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.gui.startselection.widgets
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.startselection.StarterSelectionScreen
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.config.starter.RenderableStarterCategory
@@ -37,7 +38,7 @@ class CategoryList(
paneHeight,
topOffset,
entryHeight
) {
), CobblemonRenderable {
companion object {
private const val CATEGORY_BUTTON_WIDTH = 51.5f
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.gui.startselection.widgets
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
@@ -20,7 +21,7 @@ class ExitButton(
pWidth: Int, pHeight: Int,
pXTexStart: Int, pYTexStart: Int, pYDiffText: Int,
onPress: OnPress
): Button(pX, pY, EXIT_BUTTON_WIDTH.toInt(), EXIT_BUTTON_HEIGHT.toInt(), "cobblemon.ui.starter.narrator.backbutton".asTranslated(), onPress, DEFAULT_NARRATION) {
): Button(pX, pY, EXIT_BUTTON_WIDTH.toInt(), EXIT_BUTTON_HEIGHT.toInt(), "cobblemon.ui.starter.narrator.backbutton".asTranslated(), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val EXIT_BUTTON_WIDTH = 15.95F
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.gui.startselection.widgets.preview
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
@@ -22,7 +23,7 @@ class ArrowButton(
right: Boolean,
private val texture: ResourceLocation = if (right) RIGHT_ARROW_BUTTON_RESOURCE else LEFT_ARROW_BUTTON_RESOURCE,
onPress: OnPress
) : Button(pX, pY, pWidth, pHeight, Component.empty(), onPress, DEFAULT_NARRATION) {
) : Button(pX, pY, pWidth, pHeight, Component.empty(), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private val RIGHT_ARROW_BUTTON_RESOURCE = cobblemonResource("textures/gui/starterselection/starterselection_arrow_right.png")
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.startselection.widgets.preview
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.ColourLibrary
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
@@ -25,7 +26,7 @@ class SelectionButton(
pX: Int, pY: Int,
pWidth: Int, pHeight: Int,
onPress: OnPress
): Button(pX, pY, pWidth, pHeight, Component.literal("SelectionButton"), onPress, DEFAULT_NARRATION) {
): Button(pX, pY, pWidth, pHeight, Component.literal("SelectionButton"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private val buttonTexture = cobblemonResource("textures/gui/starterselection/starterselection_button.png")
@@ -22,6 +22,7 @@ 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.CobblemonRenderable
import com.cobblemon.mod.common.client.gui.ExitButton
import com.cobblemon.mod.common.client.gui.TypeIcon
import com.cobblemon.mod.common.client.gui.summary.widgets.EvolutionSelectScreen
@@ -63,7 +64,7 @@ import net.minecraft.sounds.SoundEvent
* @param selection The index the [party] will have as the base [selectedPokemon].
*/
class Summary private constructor(party: Collection<Pokemon?>, private val editable: Boolean, private val selection: Int): Screen(
Component.translatable("cobblemon.ui.summary.title")), Schedulable {
Component.translatable("cobblemon.ui.summary.title")), Schedulable, CobblemonRenderable {
companion object {
const val BASE_WIDTH = 331
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
@@ -38,7 +39,7 @@ class SummaryButton(
private val boldText: Boolean = true,
private val largeText: Boolean = true,
private val textScale: Float = 1F
): Button(buttonX.toInt(), buttonY.toInt(), buttonWidth.toInt(), buttonHeight.toInt(), text, clickAction, DEFAULT_NARRATION) {
): Button(buttonX.toInt(), buttonY.toInt(), buttonWidth.toInt(), buttonHeight.toInt(), text, clickAction, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
const val TEXT_HEIGHT = 9
@@ -23,7 +23,8 @@ class ModelWidget(
var pokemon: RenderablePokemon,
val baseScale: Float = 2.7F,
var rotationY: Float = 35F,
var offsetY: Double = 0.0
var offsetY: Double = 0.0,
val playCryOnClick: Boolean = false,
): SoundlessWidget(pX, pY, pWidth, pHeight, Component.literal("Summary - ModelWidget")) {
companion object {
@@ -70,6 +71,15 @@ class ModelWidget(
matrices.popPose()
}
override fun onClick(pMouseX: Double, pMouseY: Double) {
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
if (this.isHovered) playCry()
return super.mouseClicked(pMouseX, pMouseY, pButton)
}
private fun playCry() {
if (playCryOnClick) {
state.activeAnimations.clear()
state.addFirstAnimation(setOf("cry"))
}
}
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.summary.widgets
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler.MAX_NAME_LENGTH
@@ -28,7 +29,7 @@ class NicknameEntryWidget(
): EditBox(
Minecraft.getInstance().font,
x, y, width, height, text
) {
), CobblemonRenderable {
var pokemonName = ""
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.summary.widgets.common
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.Minecraft
@@ -29,7 +30,7 @@ abstract class SummaryScrollList<T : ObjectSelectionList.Entry<T>>(
HEIGHT, // height
0, // top
slotHeight
) {
), CobblemonRenderable {
companion object {
const val WIDTH = 108
const val HEIGHT = 112
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.gui.summary.widgets.screens
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
@@ -24,7 +25,7 @@ class SummaryTab(
val label: MutableComponent? = null,
val icon: ResourceLocation? = null,
onPress: OnPress
): Button(pX, pY, 50, 13, label, onPress, DEFAULT_NARRATION) {
): Button(pX, pY, 50, 13, label, onPress, DEFAULT_NARRATION), CobblemonRenderable {
private var isActive = false
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
Loaded 100 of 1015 files, more files were not shown because too many files have changed in this diff. Show more