Compare commits

..
149 Commits
Author SHA1 Message Date
Paul 2e3302bdec not snap 2024-12-25 08:40:38 +10:00
Paul f77af7c954 Merge remote-tracking branch 'origin/lang-updates' 2024-12-25 07:56:12 +10:00
Hiroku 63ed488b03 Merge branch 'quic-molang-additions' into 'main'
[1.6] Add entity type id molang function

See merge request cable-mc/cobblemon!1415
2024-12-24 21:50:53 +00:00
Hiroku fcce15e210 Edit MoLangFunctions.kt 2024-12-24 21:50:15 +00:00
Test d816710566 Changelog shenanigans 3 [skip-ci] 2024-12-24 21:48:16 +00:00
Hiroku c8a8e689cc Merge branch 'actually-on-hit' into 'main'
[1.6] make THROWN_POKEBALL_HIT actually do what it says on the tin

See merge request cable-mc/cobblemon!1418
2024-12-24 21:47:49 +00:00
Paul 222f6dd955 Changelog shenanigans 2 [skip-ci] 2024-12-25 07:46:03 +10:00
amo f61efb11b1 fix silly 2024-12-24 14:58:03 +00:00
Briar 19b4d841f4 im a FOOL 2024-12-24 14:31:31 +00:00
Briar 704320f1bc oops 2024-12-24 14:22:42 +00:00
Briar e5480bd05b make THROWN_POKEBALL_HIT actually do what it says on the tin 2024-12-24 14:17:57 +00:00
Briar 8d504d23e1 Update file MoLangFunctions.kt 2024-12-24 13:58:51 +00:00
Paul 2912ffdad9 Changelog shenanigans [skip-ci] 2024-12-24 23:38:25 +10:00
Paul 986f22c5a5 Added clamping for pokemon angles in the hopes of killing the watchdog killer 2024-12-24 18:58:10 +10:00
Hiroku 880f6de77a Merge branch 'fix-no-ai-property' into 'main'
Fix no_ai property not working when set to false

Closes #1270

See merge request cable-mc/cobblemon!1413
2024-12-24 08:01:50 +00:00
lionandHiroku 7f87b0f184 Fix no_ai property not working when set to false 2024-12-24 08:01:50 +00:00
Hiroku a811a823e6 Merge branch 'fix-shiny-magikarp-jump-variations' into 'main'
Fix shiny Magikarp jump variations

See merge request cable-mc/cobblemon!1416
2024-12-24 08:01:20 +00:00
lionandHiroku a45999894b Fix shiny Magikarp jump variations 2024-12-24 08:01:19 +00:00
Hiroku eeba80e7e7 Merge branch 'patch-1' into 'main'
Galarian Mr.Mime typo

See merge request cable-mc/cobblemon!1414
2024-12-24 08:00:17 +00:00
Briar 97b20158e9 Update file MoLangFunctions.kt 2024-12-24 02:28:33 +00:00
VanironCZ 586eaa9135 Fix typo, make form work 2024-12-24 00:58:06 +00:00
Polymeta dc7925ab3e Merge branch 'ci-fixes' into 'main'
Fix CI

See merge request cable-mc/cobblemon!1412
2024-12-23 22:46:40 +00:00
complacentdevandPolymeta 8986159a25 Fix CI 2024-12-23 22:46:39 +00:00
Test b864f715ea update item sprites 2024-12-23 17:24:19 -05:00
Nick 02b7d5eeae Merge branch 'fix/neoforge-payload-logging' into 'main'
No longer log all packets by state, just register

See merge request cable-mc/cobblemon!1411
2024-12-23 21:05:03 +00:00
Nick 614be610d4 No longer log all packets by state, just register 2024-12-23 13:02:40 -08:00
Polymeta 1084c7a289 Merge branch 'ci' into 'main'
Make Cobblemon 20% Smaller

See merge request cable-mc/cobblemon!1224
2024-12-23 17:55:16 +00:00
complacentdevandPolymeta 110d6dc828 Make Cobblemon 20% Smaller 2024-12-23 17:55:16 +00:00
Paul d98d68c7d4 Added cancellation and handler ordering support to flows, more cleanup for Pokedex event, changelog for flows, removed old junk 2024-12-23 21:50:44 +10:00
Hiroku 6369d876e3 Merge branch 'HorizontalTeamAlignmentForMoveTargeting' into 'main'
Horizontal team alignment for move targeting

See merge request cable-mc/cobblemon!1410
2024-12-23 10:31:06 +00:00
Hiroku 8388a53017 Merge branch 'date-and-timolang' into 'main'
[1.6] system time and date molang

See merge request cable-mc/cobblemon!1405
2024-12-23 10:17:04 +00:00
Hiroku 3a59d7d7c9 Edit MoLangFunctions.kt 2024-12-23 10:08:03 +00:00
Hiroku 3d9d3318b1 Merge branch 'cancelable-dex-knowledge' into 'main'
[1.6] Cancelable dex data event, split into pre & post

See merge request cable-mc/cobblemon!1403
2024-12-23 09:26:26 +00:00
Paul d032e0449b Tweaks for inbuilt region bias pack and changelog 2024-12-23 19:25:05 +10:00
Hiroku bcdbb19a75 Merge branch 'fix-pasture-shiny-effect' into 'main'
Fix shiny pasture Pokémon playing the shiny effect incorrectly

Closes #1257

See merge request cable-mc/cobblemon!1409
2024-12-23 09:24:36 +00:00
lionandHiroku 2181cdb4ef Fix shiny pasture Pokémon playing the shiny effect incorrectly 2024-12-23 09:24:36 +00:00
JazzMcNade 24257a4c6e Swapped team alignment from vertical to horizontal 2024-12-23 02:12:19 -06:00
Test 2a293def4f Merge branch 'inbuilt-packs' into 'main'
Setup inbuilt resource packs for various things

See merge request cable-mc/cobblemon!1408
2024-12-23 07:28:33 +00:00
Hiroku a3d77dd2a0 Merge branch 'CounterMovesUITargetingFix' into 'main'
Fix UI targeting for MetalBurst, Counter, MIrrorCoat, etc

See merge request cable-mc/cobblemon!1407
2024-12-23 06:51:43 +00:00
Paul 311f0e3192 Setup inbuilt resource packs for various things 2024-12-23 16:30:20 +10:00
JazzMcNade be2099130b Fix UI targeting for MetalBurst, Counter, MIrrorCoat, etc 2024-12-23 00:18:35 -06:00
Hiroku 6ebe0b9c7e Merge branch 'fix-spectators-obscuring-line-of-sight' into 'main'
Fix spectators obscuring line of sight when interacting with other players

Closes #1261

See merge request cable-mc/cobblemon!1406
2024-12-23 04:11:58 +00:00
lionandHiroku dde5c00789 Fix spectators obscuring line of sight when interacting with other players 2024-12-23 04:11:57 +00:00
amo d980faed64 resolve threads 2024-12-23 03:22:39 +00:00
Hiroku 7a80bc54ea Merge branch 'disable-entity-labels-when-crouching-only' into 'main'
Set 'displayEntityLabelsWhenCrouchingOnly' config default to false

See merge request cable-mc/cobblemon!1390
2024-12-23 02:53:53 +00:00
lionandHiroku f207206b13 Set 'displayEntityLabelsWhenCrouchingOnly' config default to false 2024-12-23 02:53:52 +00:00
amo edf510d8e8 split dex data changed event into pre and post, make pre cancelable 2024-12-23 02:30:38 +00:00
Hiroku 721384547f Merge branch 'feature/small-fixes' into 'main'
(1.6) Small fixes

Closes #1188 and #1264

See merge request cable-mc/cobblemon!1404
2024-12-23 01:36:36 +00:00
PolymetaandHiroku ce5189e83a (1.6) Small fixes 2024-12-23 01:36:36 +00:00
amo d7fc09b967 split dex data changed event into pre and post, make pre cancelable 2024-12-22 22:47:45 +00:00
Gustavo PuerariandWeblate 703eb7645c Translated using Weblate (Portuguese (Brazil))
Currently translated at 34.8% (2228 of 6391 strings)

Translation: Cobblemon/Mod
Translate-URL: http://lang.cobblemon.com/projects/cobblemon/mod/pt_BR/
2024-12-22 21:41:42 +00:00
Polymeta 604c184029 Merge branch 'This-time-I-wont-mess-up' into 'main'
Let's try this again

See merge request cable-mc/cobblemon!1402
2024-12-22 19:00:29 +00:00
Slippy 727ada3e00 Let's try this again 2024-12-22 12:51: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_CrabandPolymeta 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 FarmerandPolymeta 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
lionandPolymeta 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
lionandHiroku 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 PuerariandWeblate 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
TeggyandWeblate 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 PuerariandWeblate 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ñoandWeblate 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
TeggyandWeblate 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
VeraxielandPolymeta 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
lionandHiroku 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
Gustavo Felippi PuerariandWeblate 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
Segfault Guy 439161c180 Merge remote-tracking branch 'origin/main' into ihatebugtypes 2024-12-13 23:39:22 -05:00
TeggyandWeblate 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 GhastandWeblate 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 PuerariandWeblate 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
TeggyandWeblate 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
Gustavo Felippi PuerariandWeblate 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
TeggyandWeblate 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 GhastandWeblate 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 PuerariandWeblate 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 SalgueiroandWeblate 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
Zack the GhastandWeblate 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
MiaandWeblate 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 GhastandWeblate 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 ChuchokjatupornandWeblate 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 ChuchokjatupornandWeblate 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 ChuchokjatupornandWeblate 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 SalgueiroandWeblate 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
MiaandWeblate 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 ChuchokjatupornandWeblate 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 IdriciandWeblate 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 SalgueiroandWeblate 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 ChuchokjatupornandWeblate 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 SalgueiroandWeblate 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 IdriciandWeblate 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 ChuchokjatupornandWeblate 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 SalgueiroandWeblate 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ñoandWeblate 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 IdriciandWeblate 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
阿鱼andWeblate 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 SalgueiroandWeblate 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 IdriciandWeblate 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
GottvaterNougatKoenigandWeblate 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
MiaandWeblate 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
854 changed files with 12242 additions and 7872 deletions
+148 -29
View File
@@ -3,23 +3,155 @@ image: amazoncorretto:21
before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle
# TODO add client reference test process, search for import com.cobblemon.mod.common.client
stages:
- preprocessing
- packsquash
- replaceresources
- build
- deploy
#TODO add client reference test process, search for import com.cobblemon.mod.common.client
check_assets_cache:
stage: preprocessing
script:
- echo "Checking if cached hash matches current hash"
# Calculate the current hash
- find common/src/main/resources/assets common/src/main/resources/data -type f -exec sha256sum {} + | sort -k 2 | sha256sum > current_hash.txt
- echo "Current hash:"
- cat current_hash.txt
# Check for the existence of the previous hash
- if [[ -f assets_data_hash.txt ]]; then
echo "Previous cached hash found:";
cat assets_data_hash.txt;
if cmp -s assets_data_hash.txt current_hash.txt; then
echo "Hashes match, skipping PackSquash";
rm -f run_packsquash.flag || true;
else
echo "Hashes differ, PackSquash needed";
touch run_packsquash.flag;
fi;
else
echo "No cached hash found, marking PackSquash as required";
touch run_packsquash.flag;
fi
# Save the current hash for future runs
- echo "Saving current hash to cache";
- cp current_hash.txt assets_data_hash.txt
artifacts:
paths:
- current_hash.txt
- assets_data_hash.txt
- run_packsquash.flag
expire_in: 7 days
cache:
key: "cache-${CI_COMMIT_REF_NAME}"
paths:
- assets_data_hash.txt
- ./compressed_pack.zip
setup_resource_pack:
stage: preprocessing
script:
- echo "Setting up fake resource pack"
- mkdir ./fake_resource_pack
- cp -r common/src/main/resources/assets common/src/main/resources/data ./fake_resource_pack/
- echo '{"pack":{"pack_format":34,"description":"Fake Cobblemon Pack"}}' > ./fake_resource_pack/pack.mcmeta
artifacts:
paths:
- ./fake_resource_pack/
expire_in: 7 days
setup_packsquash:
stage: preprocessing
script:
- echo "Installing wget & unzip"
- yum install -y wget unzip
- echo "Downloading PackSquash"
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.0/PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip
- unzip PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip -d ./packsquash_bin
- echo "Creating PackSquash options.toml"
- |
cat <<EOF > ./options.toml
pack_directory = "./fake_resource_pack/"
output_file_path = "./compressed_pack.zip"
zip_spec_conformance_level = "high"
['**/*?.ogg']
transcode_ogg = false
two_pass_vorbis_optimization_and_validation = false
sampling_frequency = 999999
empty_audio_optimization=false
EOF
artifacts:
paths:
- ./packsquash_bin/
- ./options.toml
expire_in: 7 days
default:
artifacts:
expire_in: 7 days
run_packsquash:
stage: packsquash
dependencies:
- check_assets_cache
- setup_resource_pack
- setup_packsquash
script:
- ls -l
- if [[ ! -f ./compressed_pack.zip || -f run_packsquash.flag ]]; then
echo "Running PackSquash";
chmod +x ./packsquash_bin/packsquash;
./packsquash_bin/packsquash ./options.toml;
else
echo "Skipping PackSquash; no changes detected and compressed pack exists";
fi
cache:
key: "cache-${CI_COMMIT_REF_NAME}"
policy: pull-push
paths:
- assets_data_hash.txt
- ./compressed_pack.zip
artifacts:
paths:
- ./compressed_pack.zip
replace_resources:
stage: replaceresources
dependencies:
- run_packsquash
script:
- echo "Installing unzip"
- yum install -y unzip
- echo "Unzipping compressed pack"
- mkdir temp_unpack
- unzip ./compressed_pack.zip -d temp_unpack
- echo "Removing original assets and data"
- rm -rf common/src/main/resources/assets
- rm -rf common/src/main/resources/data
- echo "Replacing assets and data"
- mv temp_unpack/assets common/src/main/resources/
- mv temp_unpack/data common/src/main/resources/
artifacts:
paths:
- common/src/main/resources/
build:
stage: build
only:
- branches@cable-mc/cobblemon
dependencies:
- replace_resources
script:
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew build
cache:
key: "$CI_COMMIT_REF_NAME"
policy: push
artifacts:
paths:
- neoforge/build/libs
- fabric/build/libs
@@ -28,39 +160,26 @@ publish:
stage: deploy
dependencies:
- build
cache:
key: "CI_COMMIT_REF_NAME"
policy: pull
paths:
- neoforge/build/libs/*.jar
- fabric/build/libs/*.jar
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_PROJECT_PATH == "cable-mc/cobblemon" && $CI_COMMIT_BRANCH == "main"'
script:
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew publish
# Separate step to deploy the artifacts, save Norry the headache of keeping even more shit around
deploy:
stage: deploy
dependencies:
- build
when: manual
cache:
key: "$CI_COMMIT_REF_NAME"
policy: pull
artifacts:
paths:
- neoforge/build/libs/*.jar
- fabric/build/libs/*.jar
script:
deploy_artifacts:
stage: deploy
dependencies:
- build
script:
- echo "Collecting artifacts..."
- mv neoforge/build/libs/*+*.jar ./
- mv fabric/build/libs/*+*.jar ./
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
- for f in *.jar; do mv "$f" "$(echo "$f" | sed s/+/b$CI_PIPELINE_IID+/)"; done
artifacts:
expire_in: 28 days
paths:
- ./*.jar
# - neoforge/build/libs/*+*.jar
# - fabric/build/libs/*+*.jar
+81 -92
View File
@@ -4,59 +4,54 @@
### Additions
- Added the Pokédex as a craftable item that can be placed on lecterns.
- Added Pokémon (and item) fishing using modified fishing rods - Poké Rods! You'll need a Poké Rod smithing template, a fishing rod, and some type of Poké Ball. Each Poké Ball makes a differently themed rod. Why not?
- Added Pokémon (and item) fishing using modified fishing rods - Poké Rods! You'll need a Poké Rod smithing template, a fishing rod, and some type of Poké Ball. Each Poké Ball makes a differently themed rod because it's cool.
- Added Lure Ball functionality, increasing the catch rate of Pokémon that were caught on a fishing rod.
- Added Repeat Ball functionality, increasing the catch rate of Pokémon that are already registered as caught in a player's Pokédex.
- Added property chaining support for duplicate CustomPokemonPropertyType elements.
- Added flat level battling with options to set all Pokémon to level 50, 100, or 5 for the duration of a battle. No experience or EVs are granted for a flat battle.
- Added `aspect` and `unaspect` PokemonProperty arguments (which also includes commands such as `/pokemonedit`, `/spawnpokemon`, and `/givepokemon`) to allow forcing or un-forcing an aspect on a Pokémon.
- Added `type` alternatively `elemental_type` PokemonProperty argument, this is only used for filtering and is not applied to Pokémon. Example `type=fire` would be true for Charmander but false for Squirtle.
- Added support for Double Battles, Triple Battles, and Multi-battles.
- Added raft platforms for non-swimming, non-flying Pokémon to stand on during battles that take place on the water's surface (Flying Pokémon will fly over water in battle, and water breathing Pokémon will swim in water during battle).
- Added smarter send-out positions for Pokémon in battle. They should get in your way less!
- CriticalCaptures and Pokédex progress capture multiplier now work with the Pokédex.
- Added extra visuals to early berry growth stages.
- Moves impacted by the abilities Pixelate, Refrigerate, Aerilate, Galvanize, and Normalize now display as their altered typing.
- Added Polished Tumblestone and Tumblestone Brick block sets from Tumblestone, Black Tumblestone, and Sky Tumblestone.
- Added Metronome, Protective Pads, Punching Glove, Room Service, Scope Lens, Shed Shell, Terrain Extender, Throat Spray, Utility Umbrella, Wide Lens, and Zoom Lens held items
- Added particles for moves: Watersport, Mud Sport, and Psychic.
- Added Fire, Water, Thunder, Leaf, Ice, Sun, Moon, Shiny, Dawn, and Dusk Stone storage blocks.
- Added Eject Pack, Metronome, Protective Pads, Punching Glove, Room Service, Scope Lens, Shed Shell, Terrain Extender, Throat Spray, Utility Umbrella, Wide Lens, and Zoom Lens held items
- Added `stonjourner_henge_ruins`, `luna_henge_ruins`, and `sol_henge_ruins` structures.
- Added a `battleInvulnerability` gamerule to make players invulnerable to any damage during a battle.
- Added a `mobTargetInBattle` gamerule to exclude players from being targeted by mobs during a battle.
- Added battle log messages for switching out Pokémon.
- Added Evolution particles and sounds for Pokémon that are sent out when evolution is started.
- Added a Nurse profession that can be unlocked by having villagers claim a healing machine block.
- Added Pokémon Centers to all 5 village types.
- Added a `natural` block state property for the healing machine block; when property is set to true, the block will have a different texture and drop an iron ingot instead of itself.
- New config setting `displayEntityNameLabel` and `displayEntityLabelsWhenCrouchingOnly` to control what and when is displayed for the pokemon label
- `/freezepokemon` command to pause a Pokémon's animation at a specific point in time.
- Added `no_ai` and `freeze_frame` options to the `/spawnpokemon` command.
- Added shiny Pokémon effects.
- Added effects for the burn status effect.
- Added effects for the moves: Psychic, Water Sport, and Mud Sport.
- Added a new universal locator called `top`.
- Added `moves` option to Pokémon properties, allowing you to set the moves of a Pokémon in commands and spawn files using comma-separated move names.
- Added shiny Pokémon effects.
- Added shiny Pokémon particle effects and sounds to help find them.
- Added effects for the burn status effect.
- Added effects for the moves: Seismic Toss, Withdraw, Bite, Crunch, Super Fang, Hyper Fang, Pursuit, Mist, Haze, Lick, Kinesis, Psychic, Water Sport, and Mud Sport.
- Added a new universal locator called `top`.
- Added shiny Pokémon particles with sound effects.
- Added extra visuals to early berry growth stages.
- Added Polished Tumblestone and Tumblestone Brick block sets from Tumblestone, Black Tumblestone, and Sky Tumblestone.
- Moves impacted by the abilities Pixelate, Refrigerate, Aerilate, Galvanize, and Normalize now display as their altered typing.
- Added Fire, Water, Thunder, Leaf, Ice, Sun, Moon, Shiny, Dawn, and Dusk Stone storage blocks.
- Added Eject Pack, Metronome, Protective Pads, Punching Glove, Room Service, Scope Lens, Shed Shell, Terrain Extender, Throat Spray, Utility Umbrella, Wide Lens, and Zoom Lens held items.
- Added a full evolution particle effect for Pokémon that are sent out when evolution is started.
- Added a Nurse profession that can be unlocked by having villagers claim a healing machine block.
- Pokémon are now animated when seen in any GUI that isn't the party GUI.
- Added animation and sounds for trading.
- Added icons for pending trade, team-up, and battle requests from other players.
- Added `/spawnnpc` and `/spawnnpcat` commands.
- Pokémon are now animated when seen in any GUI that isn't the party GUI.
- Quirk animations can now occur for Pokémon that are shoulder mounted.
- Added `fishing boat` structures that contain an Explorer Map leading to a shipwreck cove and a Poké Rod Smithing Template.
- Added `submerged_shipwreck_cove` and `lush_shipwreck_cove` structures.
- Added new sounds for Poké Balls bouncing off of Pokémon and landing on the ground during capture.
- Added a unique set of sounds for Ancient Poké Balls.
- Added a sound for using Exp Candy and Rare Candy items.
- Added raft platforms for non-swimming, non-flying Pokémon to stand on during battles that take place on the water's surface. (Flying Pokémon will fly over water in battle, and water breathing Pokémon will swim in water during battle.)
- Added revamped Poké Ball animation for Pokémon breaking out.
- Added battle log messages for switching out Pokémon.
- Added config setting `displayEntityNameLabel` and `displayEntityLabelsWhenCrouchingOnly` to control what and when is displayed for the pokemon label.
- Added `no_ai` and `freeze_frame` options to the `/spawnpokemon` command.
- Added `moves` option to Pokémon properties, allowing you to set the moves of a Pokémon in commands and spawn files using comma-separated move names.
- Added a `natural` block state property for the healing machine block; when property is set to true, the block will have a different texture and drop an iron ingot instead of itself.
- Added a `battleInvulnerability` gamerule to make players invulnerable to any damage during a battle.
- Added a `mobTargetInBattle` gamerule to exclude players from being targeted by mobs during a battle.
- Added a `/freezepokemon` command to pause a Pokémon's animation at a specific point in time.
- Added `/spawnnpc` and `/spawnnpcat` commands.
- Added `hiddenability=false` option to `/spawnpokemon` and `/pokemonedit` commands, allowing the Pokémon's ability to be reverted to a normal ability.
- Added `aspect` and `unaspect` PokemonProperty arguments (which also includes commands such as `/pokemonedit`, `/spawnpokemon`, and `/givepokemon`) to allow forcing or un-forcing an aspect on a Pokémon.
- Added `type` alternatively `elemental_type` PokemonProperty argument, this is only used for filtering and is not applied to Pokémon. Example `type=fire` would be true for Charmander but false for Squirtle.
### Structures Added
- Fishing boat structure that contain an Explorer Map leading to a shipwreck cove and a Poké Rod Smithing Template.
- Stonjourner Henge Ruins, Luna Henge Ruins, and Sol Henge Ruins.
- Submerged Shipwreck Cove and Lush Shipwreck Cove.
- Pokémon Centers to all 5 village types.
### Pokémon Added
#### Gen 1
- Alola Bias Cubone
- Alola Bias Cubone (built-in resource pack)
- Alolan Marowak
#### Gen 2
@@ -71,6 +66,7 @@
- Octillery
- Mantine
- Smeargle
- Delibird
#### Gen 3
- Slakoth
@@ -142,8 +138,8 @@
- Dondozo
#### Unique Forms
- Magikarp Jump Variants
- Gyarados Jump Variants
- Magikarp Jump variants for Magikarp
- Magikarp Jump variants for Gyarados (built-in resource pack, enabled by default on Fabric)
### Added cries to the following Pokémon
- Sandshrew, Sandslash
@@ -250,6 +246,7 @@
### Model updates for the following Pokémon
- Bulbasaur, Ivysaur, Venusaur
- Charmander, Charmeleon, Charizard
- Caterpie
- Kakuna, Beedrill
- Lapras
- Porygon, Porygon2, Porygon-Z
@@ -285,9 +282,11 @@
- Phantump, Trevenant
- Litten, Torracat, Incineroar
- Popplio, Brionne, Primarina
- Mudbray
- Lurantis
- Scorbunny, Cinderace
- Quaxly
- Skeledirge
- Tatsugiri
### Changes
@@ -297,43 +296,37 @@
- Adjusted volumes of sounds made by Display Cases, Berry Bushes, Energy Root, Medicinal Leek, Vivichoke, Mints, Revival Herbs and Gilded Chests.
- Changes to mulch buffs/durations.
- Updated potion sprites.
- Link Cable recipe has been redesigned.
- Changed Link Cable recipe to be much cheaper.
- Updated sounds for Medicinal Leeks, Big Roots, Energy Roots and Revival Herbs.
- Updated UI sounds for clicking and evolving Pokémon.
- Updated cries for Chansey, Crobat, Hoothoot, Noctowl.
- Removed the interchangeable evolution results for the first stage Hisuian starters to prevent confusion. The method still exists for stage 2 to 3, but stage 1 to 2 was not distinguishable enough for many users.
- Bulbasaur, Ivysaur, Venusaur, Kakuna, Beedrill, Snorlax, Munchlax, Krabby, Kingler, Lurantis, Horsea, Seadra, Kingdra, Litten, Torracat, Incineroar, Mudkip, Marshtomp, Swampert, Scorbunny, Cinderace, Prinplup, Empoleon, Relicanth, Goldeen, Seaking, Shellder, Cloyster, Tatsugiri, Igglybuff, Jigglypuff, Wigglytuff, Krookodile, Gible, Gabite, Garchomp, Rhyhorn, Rhydon, Rhyperior, and Carvanha received model updates.
- Vivillon wings will stop being clear when you remove any Vivillon related resourcepacks. The default pattern will be the meadow wings.
- Adjusted Pokémon sendout positions for single battles.
- Wild Pokémon interaction range increased to 12 blocks (from 10 blocks).
- Player trade range increased to 12 blocks (from 10 blocks).
- PvP battle range increased to 32 blocks (from 10 blocks).
- Spectate range increased to 64 blocks (from 10 blocks).
- The inventory key now closes our GUIs if they are open, mirroring how Minecraft screens usually work.
- The noise from the pasture and PC blocks being interacted with now activates Sculk sensors.
- Updated dialogue GUI assets with proper assets.
- Updated dialogue GUI assets with proper assets not made by a programmer. Well, it was still a programmer, but- someone who can also draw!
- Updated party switching interface when in battle.
- Relic coin pouches can now be waterlogged.
- Pokémon name and level labels are now only visible when crouching by default. Set the `displayEntityLabelsWhenCrouchingOnly` config to `false` to always have them displayed.
- The "Press R to start battle prompt" will now disappear after a player's first battle has been won.
- The default number of digits for the Pokédex number in the summary has been increased, from 3 to 4.
- The "Press R to start battle prompt" will now disappear after a player's first battle has been won. You've probably figured that detail out by then.
- The default number of digits for the Pokédex number in the summary has been increased, from 3 to 4. There sure are a lot of Pokémon these days.
- The pasture block model's screen is now off by default.
- The Poké Balls creative tab is now named Utility Items as it also encompasses Poké Rod and Pokédex items.
- Moves can now be benched without specifying a replacement move, allowing for empty move slots.
- Moves learned via Sketch now persist after battle.
- Updated potion sprites
- Removed the interchangeable evolution results for the first stage Hisuian starters to prevent confusion. The method still exists for stage 2 to 3, but stage 1 to 2 was not distinguishable enough for many users.
- Hidden Power now displays its effective typing.
- Updated particles for moves: Confusion, Protect, Sand Attack, and Quick Attack.
- Updated particles for status effects: Paralysis, Poison, and Sleep.
- Updated particles on Gastly.
- Revamped stat buff and de-buff particles.
- Improved the performance of display cases that contain Pokémon photos.
- Updated sounds for Poké Balls.
- Updated the Poké Ball animation for Pokémon breaking out.
- Updated sounds for Poké Balls closing, opening and for Pokémon breaking out.
- Improved the performance of display cases that contain Pokémon Model items.
- Removed species Base Stats from the summary interface as it is now viewable within the Pokédex.
- Changed summary tab text labels to icons.
- Changed summary tab text labels to icons. You'll get used to them. Or else.
- Clicking the summary interface exit button while the swap moves or evolve screen is open will cause the interface to switch back to the party screen. The button will exit the interface otherwise.
- Ancient Poke Balls now jump once rather than shaking 3 times when capturing Pokémon.
- The jump height indicate the number of shakes that would have occurred.
@@ -343,12 +336,15 @@
- 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. ... [But I have an idea.](https://tenor.com/view/star-wars-more-gif-21856591)
- Region-biased Pokémon forms are now optional to a built-in resource pack. This pack is enabled by default for Fabric. For NeoForge users, all our built-in resource packs default to disabled because that's all it supports right now.
- Update item sprites for Cell Battery, Chipped Pot, Covert Cloak, Cracked Pot, Masterpiece Teacup, Red Card, Sachet, and Unremarkable Teacup.
### Fixes
- Fixed Ability Patches not reverting Hidden Abilities back to Normal Abilities.
- Fixed awarding Pokémon experience upon forfeiting battles.
- Scaled down Amaura's fetus model to avoid clipping through the tank while animating.
- Fixed Cubone's cry not having a sound.
- Fixed Cubone's cry not having a sound (as if that Pokémon needed to be more tragic).
- Fixed the sendout sound erroneously playing when a wild Pokémon breaks out of a Poké ball.
- Flamethrower is no longer missing sounds.
- Fixed the Seafloor spawning context not being a usable context.
@@ -356,64 +352,58 @@
- Fixed Gilded Chests not dropping the chest itself when broken, only the contents.
- Fixed Pokémon losing their Hidden Ability through evolution if the middle stage did not have a Hidden Ability.
- Hidden Power no longer plays the water type action effect (It now plays the normal type action effect).
- Fixed Chimchar and Monferno T-posing whenever they sleep.
- Fixed Cetitan's cry breaking its walk and sleep animations.
- Fixed Crumbling Arch not blending in with the world.
- Fixed Energy Root applying being usable on a fainted Pokémon.
- Fixed Pokémon entity not spawning when starting a battle while recalling said Pokémon.
- Fixed Crumbling Arch structures not blending in with the world.
- Fixed Energy Root being usable on a fainted Pokémon.
- Fixed Pokémon not being sent out when starting a battle while recalling said Pokémon.
- Fixed species comparison not using namespace for both sides in `PokemonProperties.isSubsetOf`.
- Fixed `PokemonProperties#asString` prefixing nicknames with a '$'.
- Fixed PC not saving when Pokémon was changed outside.
- Fixed shearable Pokémon not dropping correct wool colors.
- Fixed pasture spawning Pokémon inside solid blocks when closest spawning position is blocked off.
- Fixed Tumbling Down advancement not being granted by tumblestone variants.
- Improve error handling when loading spawn sets to ensure invalid configurations don't crash the server.
- Fixed empty `JsonPlayerData` files resulting in players being unable to join server/world.
- Evolution notification and UI sound is now correctly playing (again).
- Sound for evolving Pokémon through the Summary Menu is now correctly playing again.
- Fix Starter prompt not showing up.
- Fix evolution now granting Pokédex entries.
- Fix Pokédex crash when a form is looked up without ever seeing the "normal" form.
- Fixed owned poké balls floating upwards if pausing mid-transition.
- Fixed owned Poké balls floating upwards if pausing the game mid-transition (which looked absolutely hilarious).
- Fixed all mouse buttons working for Battle UI navigation (now it's only primary/left click).
- Fixed trading Pokémon setting their friendship to 0 instead of the base value.
- Fixed a scenario where a Pokémon that rolled to spawn with a special Tera type sometimes has a Tera type that is already a part of their natural typing.
- Fixed a scenario where a Pokémon that rolled to spawn with a special Tera type sometimes having a Tera type that is already a part of their natural typing.
- Fixed PokemonProperty argument suggestions for `tera` and `tera_type` not suggesting `stellar`.
- Fixed being able to stack Relic Coin Pouches on top of each other.
- Fixed Model loader generating misleading crash-reports when client is crashing.
- Fixed model loader generating misleading crash-reports when client is crashing - that resurrection tank error wasn't our fault! We're innocent, your honour!
- Big Roots and Energy Roots now share the same sounds as intended.
- Fixed sounds made by blocks playing at a lower pitch than intended.
- Fixed Chimchar and Monferno T posing whenever they sleep.
- Fixed Chimchar and Monferno comically T posing whenever they sleep.
- Fixed Cetitan's cry breaking its walk and sleep animations.
- Fixed the Magby line not having any placeholder walk animations.
- Fixed Duskull and Dusclops using skylight levels for their nether spawn data. There is no sun in the Nether!
- Fixed Hisuian Zoroark using base Zoroark stats.
- Fixed Bellossom clipping into the player head when shoulder mounted.
- Fixed Shroomish's look range to prevent it from looking higher than it should.
- Fixed Maushold's faint animations not playing. It's sadder than Tandemaus!
- Fixed Maushold's faint animations not playing. It's even sadder than Tandemaus!
- Fixed Slowking's battle idle.
- Fixed Grafaiai's walk speed to prevent model sliding.
- Fixed Maushold's faint animations not playing. It's sadder than Tandemaus!
- Fixed Slowking's battle idle.
- Fixed Grafaiai's walk speed to prevent model sliding.
- 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 reviving items throwing an exception when used in battle.
- Fixed Hisuian Sneasel using Johtonian Sneasel's cry. Johto-nian. Jotonion. Jotunheim?
- Fixed Trevenant T-posing after 8 seconds of sleeping. I also do that.
- Fixed Bewear T-posing for a bit if a wild one faints where you can see.
- Fixed Noctowl's placeholder fly animation.
- Corrected Lotad blinking animation.
- Fixed reviving items causing errors 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.
- Fixed `crumbling_arch_ruins` from generating a giant cube of air and removed the chest.
- Fixed Crumbling Arch Ruins generating a giant cube of air and removed the chest.
- Fixed possible crash on large population servers due to concurrent access of data.
- Quickly sending out and recalling Pokémon now looks smoother and can no longer be spammed to cause desync issues.
- Pokémon are now invulnerable during sendout animation and intangible during recall animation.
- Pokémon are now invincible during sendout animation and intangible during recall animation.
- Scrolling with party keybinding now behaves properly when using high scroll speed or scroll sensitivity.
- Fixed battle log GUI flashing when Battle GUI is opened.
- Bag Items used during a turn will now be refunded if the battle ends before the next turn begins.
- Pokémon whose current owner is not its Original Trainer now gains extra experience.
- Pokémon whose current owner is not its Original Trainer now gain extra experience.
- Fixed Fossil Resurrection advancement not being granted.
- Fixed village generation caps not applying for berry farms. You were not meant to see more than two berry farms per village!
- Fixed village generation caps not applying for berry farms. You were not meant to see more than two berry farms per village! This has been broken for ages but no one noticed... Hmmm... We could just remove it from here...
- Fixed the Ice Face ability activation being displayed incorrectly in a battle.
- Fixed edge case of F1 and R locking you in battle with no R functionality (requiring ESC to get out).
- Fixed Poké Ball render orientation in battle interface when capturing.
@@ -426,27 +416,23 @@
- Fixed top black border rendering in scroll interfaces in summary UI.
- Fixed aspect tracking for Advancements.
- Fixed illusion not copying aspects or caught ball.
- Delay when successfully catching a Pokémon in an Ancient Poké Ball has been increased to account for the new sounds and particles.
- 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`.
- Many types related to `Pokemon` including itself now have dedicated `Codec`, please migrate to them from the NBT/JSON/PacketBuffer write/read methods.
- `TeraTypes` now implements `Iterable`.
- `PokemonBattle` now starts on turn 0.
- SpawnCause is now an implementation of SpawningInfluence.
- Renamed Pokemon.hp to Pokemon.maxHealth to make it clearer. Backwards compatibility is provided but it is an active deprecation, please migrate away from it.
- Many types related to ``Pokemon`` including itself now have dedicated ``Codec``, please migrate to them from the NBT/JSON/PacketBuffer write/read methods.
- Serialization of PokemonStores and Pokemon themselves now require registry access, which will break some sidemods. This sucked for us more than it will suck for you! If you have a world or player instance, you can get it from there.
- ``TeraTypes`` now implements ``Iterable``.
- PokemonBattle now starts on turn 0.
- Added `forcedAspects` to Pokémon to make it easier to easily add basic aspects to a Pokémon in a way that persists. We already know that everyone is going to overuse this.
- Made the `Pokemon.aspects` setter private. This could technically break side-mods but if you are affected by this then you were using it wrong! Use `Pokemon.forcedAspects` to fix it.
- Cobblemon's main logger is properly static now.
- PokemonEntity.enablePoseTypeRecalculation can be used to disable automatic pose type recalculation.
- `PokemonEntity.enablePoseTypeRecalculation` can be used to disable automatic pose type recalculation.
- Added CollectEggEvent and HatchEggEvent for compatibility usage.
- Added events for:
- Showdown Instructions
@@ -462,32 +448,34 @@
- 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.
- Dex Information Changed (Pre and Post); 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.
- Renamed StatefulAnimation to ActiveAnimation.
- Documented the animation system.
- Allowed for SpawnSnowstormEntityParticleHandler to handle non-posable entities (due to being non-posable, locators are useless, to set the offset use the settings in the particle itself)
- Allowed for SpawnSnowstormEntityParticleHandler to handle non-posable entities (due to being non-posable, locators are useless - to set the offset use the settings in the particle itself).
- Added property chaining support for duplicate CustomPokemonPropertyType elements.
### Data Pack & Resource Pack Creators
- Added experimental `flow` datapack directory for handling events using MoLang event handlers.
- Added support for "shedders" similar to Shedinja's evolution logic.
- Fixed the placeholder `WingFlapIdle` animation so the wings are not rotating opposite to each other.
- 'player' type dialogue faces can now be explicitly stated so that NPC mods that use fake players can show in dialogue portraits.
- Added `isLeftSide` field for dialogue faces. This determines what side of dialogue box the portrait is on.
- "sounds/attacks" folder has been renamed to "sounds/move"
- `sounds/attacks` directory has been renamed to `sounds/move`.
- Moves sharing generic sounds now have unique sound events, allowing them to be changed with resource packs.
- All move sound events have been renamed to "move.NAME.SOURCE" for consistency.
- Status moves have been moved out of the 'attacks' folder and split into volatile and nonvolatile.
- 'status.badlypoison.actor' sound event has been renamed to "status.toxpoison.actor"
- Mulch and berry harvesting sound events have been renamed and moved to their respective folders in "sounds/block."
- All sounds related to evolving Pokémon have been moved to the "sounds/evolution" folder.
- Sound events for all blocks now start with "block."
- All move sound events have been renamed to `move.<NAME>.<SOURCE>` for consistency.
- Status moves have been moved out of the `attacks` directory and split into volatile and nonvolatile.
- `status.badlypoison.actor` sound event has been renamed to `status.toxpoison.actor`
- Mulch and berry harvesting sound events have been renamed and moved to their respective directories in `sounds/block`.
- All sounds related to evolving Pokémon have been moved to the `sounds/evolution` directory.
- Sound events for all blocks now start with `block`.
- Gimmighoul chest and item interaction sounds have been moved to where its cry is.
- Unused sound files and sound events have been removed.
- Poké Ball sounds are now in their animation files, making them more flexible to edit.
- Added MoLang compatibility in the isVisible property for transformed parts.
- Added q.has_aspect('some_aspect') function to animations, posers, and entity particle effects.
- Added `q.has_aspect('some_aspect')` function to animations, posers, and entity particle effects.
- Added support for conditional pose animations.
- Added a new universal locator called "top".
- Added `eggs_collected` and `eggs_hatched` Advancement triggers.
@@ -496,6 +484,7 @@
- `isTouchingWaterOrRain` has been changed to `isInWaterOrRain`
- `isSubermegedInWater` has been changed to `isUnderWater`
### Localization
- Updated translations for:
- Czech, German, Greek, Spanish, Mexican Spanish, French, Canadian French, Hungarian, Italian, Japanese, Korean, Dutch, Polish, Portuguese, Brazilian Portuguese, Russian, Ukrainian, Simplified Chinese, and Traditional Chinese
@@ -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()
@@ -121,10 +121,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(APRICORN_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(APRICORN_PLANKS.defaultMapColor()).noCollission().strength(0.5f).sound(SoundType.WOOD)))
@JvmField
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
@JvmField //if you wonder why we don't copy of OAK_WALL_SIGN, then I can tell you its because it uses Properties#dropsLike to point to the SIGN loot table, but we cant use that in our setup due to a deeper rooted issue, so falling back to this and writing dedicated (duplicated) loot tables
val APRICORN_WALL_SIGN = this.create(
"apricorn_wall_sign",
CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE)
)
@JvmField
val APRICORN_WALL_SIGN = this.create("apricorn_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_HANGING_SIGN), APRICORN_WOOD_TYPE))
val APRICORN_HANGING_SIGN = this.create(
"apricorn_hanging_sign",
CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), APRICORN_WOOD_TYPE)
)
@JvmField
val APRICORN_WALL_HANGING_SIGN = this.create("apricorn_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), APRICORN_WOOD_TYPE))
@JvmField
@@ -12,6 +12,7 @@ import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.DataRegistry
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.reactive.SimpleObservable
@@ -50,19 +51,21 @@ object CobblemonFlows : DataRegistry {
override fun reload(manager: ResourceManager) {
clientFlows.clear()
flows.clear()
val unsortedFlows = mutableMapOf<ResourceLocation, MutableList<Pair<String, ExpressionLike>>>()
val folderBeforeNameRegex = ".*\\/([^\\/]+)\\/[^\\/]+\$".toRegex()
manager.listResources("flows") { path -> path.endsWith(CobblemonScripts.MOLANG_EXTENSION) }.forEach { (identifier, resource) ->
resource.openAsReader().use { stream ->
stream.buffered().use { reader ->
try {
val expression = reader.readText().asExpressionLike()
val event = folderBeforeNameRegex.find(identifier.path)?.groupValues?.get(1)
?: throw IllegalArgumentException("Invalid flow path: $identifier. Should have a folder structure that includes the name of the event being flowed.")
if (identifier.path.startsWith("flows/client/")) {
clientFlows.getOrPut(ResourceLocation.fromNamespaceAndPath(identifier.namespace, event)) { mutableListOf() }.add(expression)
} else {
flows.getOrPut(ResourceLocation.fromNamespaceAndPath(identifier.namespace, event)) { mutableListOf() }.add(expression)
}
val flowKey = ResourceLocation.fromNamespaceAndPath(identifier.namespace, event)
unsortedFlows.putIfAbsent(flowKey, mutableListOf())
unsortedFlows[flowKey]!!.add(identifier.path to expression)
} catch (exception: Exception) {
throw ExecutionException("Error loading MoLang script for flow: $identifier", exception)
}
@@ -70,11 +73,31 @@ object CobblemonFlows : DataRegistry {
}
}
Cobblemon.LOGGER.info("Loaded ${CobblemonScripts.scripts.size} flows and ${CobblemonScripts.clientScripts.size} client flows")
unsortedFlows.forEach { (key, value) ->
value.sortBy { it.first }
if (key.path.startsWith("flows/client/")) {
clientFlows.getOrPut(key) { mutableListOf() }.addAll(value.map { it.second })
} else {
flows.getOrPut(key) { mutableListOf() }.addAll(value.map { it.second })
}
}
Cobblemon.LOGGER.info("Loaded ${flows.size} flows and ${clientFlows.size} client flows")
observable.emit(this)
}
fun run(eventResourceLocation: ResourceLocation, context: Map<String, MoValue>) {
flows[eventResourceLocation]?.forEach { it.resolve(runtime, context) }
fun run(eventResourceLocation: ResourceLocation, context: Map<String, MoValue>, cancelable: Cancelable? = null) {
if (cancelable == null) {
runtime.environment.query.functions.remove("cancel")
} else {
runtime.environment.query.addFunction("cancel") { cancelable }
}
flows[eventResourceLocation]?.forEach {
if (cancelable != null && cancelable.isCanceled) {
return
}
it.resolve(runtime, context)
}
}
}
@@ -8,25 +8,22 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.mojang.brigadier.arguments.ArgumentType
import kotlin.reflect.KClass
import net.minecraft.commands.synchronization.ArgumentTypeInfo
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.server.packs.resources.PreparableReloadListener
import net.minecraft.server.packs.resources.ResourceManager
import net.minecraft.tags.TagKey
import net.minecraft.world.level.GameRules
import net.minecraft.world.level.ItemLike
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.levelgen.GenerationStep
import net.minecraft.world.level.levelgen.placement.PlacedFeature
import kotlin.reflect.KClass
interface CobblemonImplementation {
val modAPI: ModAPI
@@ -178,16 +175,6 @@ interface CobblemonImplementation {
* @param chance The chance % of increasing the composter level, 0 to 1 expected.
*/
fun registerCompostable(item: ItemLike, chance: Float)
/**
* Registers a builtin resource pack.
*
* @param id The unique [ResourceLocation] of this pack.
* @param title The title displayed in the resource pack GUI, the description is still a part of the pack metadata.
* @param activationBehaviour The [ResourcePackActivationBehaviour] for this pack.
*/
fun registerBuiltinResourcePack(id: ResourceLocation, title: Component, activationBehaviour: ResourcePackActivationBehaviour)
}
enum class ResourcePackActivationBehaviour {
@@ -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
}
}
@@ -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)
@@ -193,7 +193,9 @@ object CobblemonEvents {
@JvmField
val POKEMON_SEEN = EventObservable<PokemonSeenEvent>()
@JvmField
val POKEDEX_DATA_CHANGED = EventObservable<PokedexDataChangedEvent>()
val POKEDEX_DATA_CHANGED_PRE = CancelableObservable<PokedexDataChangedEvent.Pre>()
@JvmField
val POKEDEX_DATA_CHANGED_POST = EventObservable<PokedexDataChangedEvent.Post>()
// Fishing
@JvmField
@@ -11,10 +11,11 @@ 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.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
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
@@ -24,20 +25,36 @@ 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,
sealed interface 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
)
}
fun getContext(): MutableMap<String, MoValue> {
return mutableMapOf(
"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
)
}
class Pre(
override val dataSource: Either<PokedexEntityData, Pokemon>,
override val knowledge: PokedexEntryProgress,
override val playerUUID: UUID,
override val record: FormDexRecord
) : PokedexDataChangedEvent, Cancelable()
class Post(
override val dataSource: Either<PokedexEntityData, Pokemon>,
override val knowledge: PokedexEntryProgress,
override val playerUUID: UUID,
override val record: FormDexRecord
) : PokedexDataChangedEvent
}
@@ -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?
@@ -47,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
@@ -56,12 +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
@@ -175,6 +180,30 @@ object MoLangFunctions {
val expression = params.getString(0).asExpressionLike()
runtime.resolve(expression)
},
"system_time_millis" to java.util.function.Function { _ ->
DoubleValue(System.currentTimeMillis())
},
// the rest of the world use dd/MM/yyyy grow up america (this comment was generated by copilot)
"date_local_time" to java.util.function.Function { _ ->
val time = System.currentTimeMillis()
val date = java.util.Date(time)
val formatted = java.text.SimpleDateFormat("DD/MM/YYYY").format(date)
StringValue(formatted)
},
"date_of" to java.util.function.Function { params ->
val time = params.getDouble(0).toLong()
val date = java.util.Date(time)
val formatted = java.text.SimpleDateFormat("DD/MM/YYYY").format(date)
StringValue(formatted)
},
"date_is_after" to java.util.function.Function { params ->
val dateA = params.getString(0)
val dateB = params.getString(1)
val format = java.text.SimpleDateFormat("DD/MM/YYYY")
val a = format.parse(dateA)
val b = format.parse(dateB)
DoubleValue(a.after(b))
}
)
val biomeFunctions = mutableListOf<(Holder<Biome>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>()
val worldFunctions = mutableListOf<(Holder<Level>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
@@ -235,6 +264,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)
@@ -408,6 +462,11 @@ object MoLangFunctions {
}
map.put("max_health") { _ -> DoubleValue(entity.maxHealth) }
map.put("name") { _ -> StringValue(entity.effectiveName().string) }
map.put("type") { _ ->
entity.registryAccess().registry(Registries.ENTITY_TYPE).get().getKey(entity.type)?.toString()?.let {
StringValue(it)
} ?: DoubleValue.ZERO
}
map.put("yaw") { _ -> DoubleValue(entity.yRot.toDouble()) }
map.put("pitch") { _ -> DoubleValue(entity.xRot.toDouble()) }
map.put("x") { _ -> DoubleValue(entity.x) }
@@ -459,7 +518,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
@@ -1,23 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.moves
enum class MoveEffectiveness(val showdownId: Int, val multiplier: Double) {
NORMAL(0, 1.0),
WEAKNESS(1, 2.0),
RESISTANCE(2, 0.5),
IMMUNITY(3, 0.0);
companion object {
fun of(showdownId: Int): MoveEffectiveness {
return entries.find { it.showdownId == showdownId }
?: throw IllegalArgumentException("Unknown MoveEffectiveness: $showdownId")
}
}
}
@@ -1,48 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.moves
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.battles.runner.ShowdownService
object TypeChart {
private val movesEffectiveness = mutableMapOf<ElementalType, MutableMap<ElementalType, MoveEffectiveness>>()
fun load() {
movesEffectiveness.clear()
val typeChartJson = ShowdownService.service.getTypeChart()
typeChartJson.keySet().forEach { type ->
val defenderType = ElementalTypes.get(type) ?: return@forEach
val moveTypes = typeChartJson.get(type).asJsonObject.get("damageTaken").asJsonObject
moveTypes.keySet().forEach innerLoop@ {
val moveType = ElementalTypes.get(it) ?: return@innerLoop
val moveEffectiveness = moveTypes.get(it).asInt
val defenderMap = movesEffectiveness.getOrPut(moveType) { mutableMapOf() }
defenderMap[defenderType] = MoveEffectiveness.of(moveEffectiveness)
}
}
}
fun getMoveEffectiveness(moveType: ElementalType, defenderTypes: List<ElementalType?>): Double {
var multiplier = 1.0
defenderTypes.filterNotNull().forEach {
multiplier *= getMoveEffectiveness(moveType, it).multiplier
}
return multiplier
}
private fun getMoveEffectiveness(moveType: ElementalType, defenderType: ElementalType): MoveEffectiveness {
return movesEffectiveness[moveType]?.get(defenderType) ?: throw IllegalArgumentException("Unknown effectiveness type: $moveType $defenderType")
}
}
@@ -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()
@@ -62,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)
@@ -150,25 +150,4 @@ abstract class AbstractPokedexManager {
open fun markDirty() {
// Save stuff
}
companion object {
const val NUM_CAUGHT_KEY = "cobblemon.pokedex.entries.caught"
const val NUM_SEEN_KEY = "cobblemon.pokedex.entries.seen"
fun getKeyForSpeciesBase(speciesId: ResourceLocation): String {
return "cobblemon.pokedex.${speciesId.path}"
}
fun getKnowledgeKeyForSpecies(speciesId: ResourceLocation): String {
return "${getKeyForSpeciesBase(speciesId)}.knowledge"
}
fun getKnowledgeKeyForForm(speciesId: ResourceLocation, formName: String): String {
return "${getKnowledgeKeyForSpecies(speciesId)}.${formName.lowercase()}"
}
fun getCaptureMethodKeyForSpecies(speciesId: ResourceLocation): String {
return "${getKeyForSpeciesBase(speciesId)}.capturemethod"
}
}
}
@@ -53,8 +53,11 @@ class FormDexRecord {
/** The genders that the dex is aware of. */
private val genders: MutableSet<Gender> = mutableSetOf()
/** Shiny states could be shiny or non-shiny - on the off chance they only saw the shiny, they shouldn't know what the normal looks like. */
private val seenShinyStates = mutableSetOf<String>() // consider: radiants in the future (radiants should just be a resource pack tbh)
private val seenShinyStates =
mutableSetOf<String>() // consider: radiants in the future (radiants should just be a resource pack tbh)
/** The current awareness of the form that the dex has. */
var knowledge = PokedexEntryProgress.NONE
private set
@@ -119,40 +122,71 @@ class FormDexRecord {
}
private fun addInformation(pokemon: Pokemon, knowledge: PokedexEntryProgress) {
genders.add(pokemon.gender)
seenShinyStates.add(if (pokemon.shiny) "shiny" else "normal")
if (knowledge.ordinal > this.knowledge.ordinal) {
this.knowledge = knowledge
}
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))
CobblemonEvents.POKEDEX_DATA_CHANGED_PRE.postThen(
PokedexDataChangedEvent.Pre(
Either.right(pokemon),
knowledge,
pokedexManager.uuid,
this
),
ifSucceeded = {
genders.add(pokemon.gender)
seenShinyStates.add(if (pokemon.shiny) "shiny" else "normal")
if (knowledge.ordinal > this.knowledge.ordinal) {
this.knowledge = knowledge
}
speciesDexRecord.addInformation(pokemon, knowledge)
speciesDexRecord.onFormRecordUpdated(this)
CobblemonEvents.POKEDEX_DATA_CHANGED_POST.post(
PokedexDataChangedEvent.Post(
Either.right(pokemon),
knowledge,
pokedexManager.uuid,
this
)
)
})
}
}
private fun addInformation(pokedexEntityData: PokedexEntityData, knowledge: PokedexEntryProgress) {
genders.add(pokedexEntityData.gender)
seenShinyStates.add(if (pokedexEntityData.shiny) "shiny" else "normal")
if (knowledge.ordinal > this.knowledge.ordinal) {
this.knowledge = knowledge
}
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))
CobblemonEvents.POKEDEX_DATA_CHANGED_PRE.postThen(
PokedexDataChangedEvent.Pre(
Either.left(pokedexEntityData),
knowledge,
pokedexManager.uuid,
this
),
ifSucceeded = {
genders.add(pokedexEntityData.gender)
seenShinyStates.add(if (pokedexEntityData.shiny) "shiny" else "normal")
if (knowledge.ordinal > this.knowledge.ordinal) {
this.knowledge = knowledge
}
speciesDexRecord.addInformation(pokedexEntityData, knowledge)
speciesDexRecord.onFormRecordUpdated(this)
CobblemonEvents.POKEDEX_DATA_CHANGED_POST.post(
PokedexDataChangedEvent.Post(
Either.left(pokedexEntityData),
knowledge,
pokedexManager.uuid,
this
)
)
}
)
}
}
/** Returns whether the given [Pokemon] and [knowledge] would add new information to the Pokédex.*/
fun wouldBeDifferent(pokemon: Pokemon, knowledge: PokedexEntryProgress): Boolean {
return pokemon.gender !in genders
|| (pokemon.shiny && "shiny" !in seenShinyStates)
|| (!pokemon.shiny && "normal" !in seenShinyStates)
|| knowledge.ordinal > this.knowledge.ordinal
|| speciesDexRecord.wouldBeDifferent(pokemon)
|| (pokemon.shiny && "shiny" !in seenShinyStates)
|| (!pokemon.shiny && "normal" !in seenShinyStates)
|| knowledge.ordinal > this.knowledge.ordinal
|| speciesDexRecord.wouldBeDifferent(pokemon)
}
fun wouldBeDifferent(pokedexEntityData: PokedexEntityData, knowledge: PokedexEntryProgress): Boolean {
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.api.drop.ItemDropMethod
import com.cobblemon.mod.common.api.entity.EntityDimensionsAdapter
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.moves.TypeChart
import com.cobblemon.mod.common.api.moves.adapters.MoveTemplateAdapter
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffect
import com.cobblemon.mod.common.api.pokemon.effect.adapter.ShoulderEffectAdapter
@@ -126,7 +125,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
it.indicateSpeciesInitialized()
// Reload this with the mod
CobblemonHeldItemManager.load()
TypeChart.load()
Cobblemon.LOGGER.info("Loaded {} Pokémon species", this.speciesByIdentifier.size)
this.observable.emit(this)
}
@@ -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))
}
}
@@ -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()
@@ -113,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
}
@@ -214,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
}
@@ -287,7 +283,6 @@ object BattleBuilder {
playerActor.battleTheme = pokemonEntity.getBattleTheme()
return if (errors.isEmpty) {
var result: BattleStartResult = errors
BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(playerActor),
@@ -296,9 +291,7 @@ object BattleBuilder {
if (!cloneParties) {
pokemonEntity.battleId = it.battleId
}
result = SuccessfulBattleStart(it)
}
result
} else {
errors
}
@@ -367,16 +360,13 @@ object BattleBuilder {
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
}
@@ -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)
}
@@ -107,7 +107,7 @@ interface Targetable {
MoveTarget.adjacentAllyOrSelf -> null
MoveTarget.adjacentFoe -> null
MoveTarget.foeSide -> getAllActivePokemon().filter { !it.isAllied(this) }
MoveTarget.scripted -> null
MoveTarget.scripted -> listOf(this)
else -> null
}
}
@@ -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)
}
}
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.battles.runner
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.battles.runner.graal.GraalShowdownService
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import java.util.UUID
/**
@@ -31,7 +30,6 @@ interface ShowdownService {
fun getAbilityIds(): JsonArray
fun getMoves(): JsonArray
fun getItemIds(): JsonArray
fun getTypeChart(): JsonObject
fun registerSpecies()
fun registerBagItems()
fun indicateSpeciesInitialized() {}
@@ -40,4 +38,4 @@ interface ShowdownService {
companion object {
val service: ShowdownService by lazy { GraalShowdownService() }
}
}
}
@@ -16,7 +16,6 @@ import com.cobblemon.mod.common.battles.ShowdownInterpreter
import com.cobblemon.mod.common.battles.runner.ShowdownService
import com.google.gson.Gson
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import java.io.File
import java.io.IOException
import java.net.URI
@@ -153,12 +152,6 @@ class GraalShowdownService : ShowdownService {
return gson.fromJson(arrayResult, JsonArray::class.java)
}
override fun getTypeChart(): JsonObject {
val getCobbledItemIdsFn = context.getBindings("js").getMember("getTypeChart")
val arrayResult = getCobbledItemIdsFn.execute().asString()
return gson.fromJson(arrayResult, JsonObject::class.java)
}
override fun registerSpecies() {
val receiveSpeciesDataFn = this.context.getBindings("js").getMember("receiveSpeciesData")
val jsArray = this.context.eval("js", "new Array();")
@@ -18,7 +18,6 @@ import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
import com.google.gson.Gson
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.OutputStreamWriter
@@ -124,13 +123,6 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
return gson.fromJson(response, JsonArray::class.java)
}
override fun getTypeChart(): JsonObject {
writer.write(">getTypeChart")
writer.flush()
val response = readMessage()
return gson.fromJson(response, JsonObject::class.java)
}
private fun sendSpeciesData(species: Species, form: FormData?) {
writer.write(">receiveSpeciesData ${gson.toJson(PokemonSpecies.ShowdownSpecies(species, form))}\n")
acknowledge()
@@ -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
@@ -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)
}
}
@@ -8,12 +8,17 @@
package com.cobblemon.mod.common.client
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonClientImplementation
import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.ResourcePackActivationBehaviour
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
import com.cobblemon.mod.common.api.storage.player.client.ClientPokedexManager
import com.cobblemon.mod.common.api.storage.player.client.ClientGeneralPlayerData
import com.cobblemon.mod.common.api.storage.player.client.ClientPokedexManager
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.client.battle.ClientBattle
import com.cobblemon.mod.common.client.gui.PartyOverlay
@@ -21,7 +26,13 @@ import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
import com.cobblemon.mod.common.client.render.ClientPlayerIcon
import com.cobblemon.mod.common.client.render.DeferredRenderer
import com.cobblemon.mod.common.client.render.block.*
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.DisplayCaseRenderer
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.block.LecternBlockEntityRenderer
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
@@ -29,7 +40,14 @@ import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererR
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.*
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BlockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.NPCModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.npc.NPCRenderer
import com.cobblemon.mod.common.client.render.pokeball.PokeBallRenderer
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer
@@ -86,6 +104,13 @@ object CobblemonClient {
GenericBedrockEntityModelRepository
)
@JvmStatic
val builtinResourcePacks = listOf<CobblemonResourcePack>(
CobblemonResourcePack(id = "adorncompatibility", name = "Adorn Compatibility", activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED, neededMods = setOf("adorn")),
CobblemonResourcePack(id = "gyaradosjump", name = "Gyarados Jump Patterns", activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED),
CobblemonResourcePack(id = "regionbiasforms", name = "Region Bias Forms", activationBehaviour = ResourcePackActivationBehaviour.DEFAULT_ENABLED),
CobblemonResourcePack(id = "uniqueshinyforms", name = "Shinies for Magikarp Jump", activationBehaviour = ResourcePackActivationBehaviour.NORMAL),
)
val overlay: PartyOverlay by lazy { PartyOverlay() }
val battleOverlay: BattleOverlay by lazy { BattleOverlay() }
@@ -0,0 +1,21 @@
/*
* 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
import com.cobblemon.mod.common.ResourcePackActivationBehaviour
import net.minecraft.network.chat.Component
class CobblemonResourcePack(
val id: String,
val name: String,
val activationBehaviour: ResourcePackActivationBehaviour,
val neededMods: Set<String> = setOf()
) {
val displayName = Component.literal(name)
}
@@ -184,15 +184,16 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
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()
@@ -200,4 +201,11 @@ class BattleGUI : Screen(battleLang("gui.title")), CobblemonRenderable {
}
return super.mouseClicked(mouseX, mouseY, button)
}
private fun minimizeBattle(): Boolean {
val battle = CobblemonClient.battle ?: return false
battle.minimised = !battle.minimised
PartySendBinding.actioned()
return true
}
}
@@ -11,11 +11,12 @@ package com.cobblemon.mod.common.client.gui.battle.subscreen
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.moves.TypeChart
import com.cobblemon.mod.common.api.text.*
import com.cobblemon.mod.common.api.text.bold
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.battles.*
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.battle.ActiveClientBattlePokemon
import com.cobblemon.mod.common.client.battle.SingleActionRequest
import com.cobblemon.mod.common.client.gui.MoveCategoryIcon
import com.cobblemon.mod.common.client.gui.TypeIcon
@@ -23,16 +24,12 @@ import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.math.toRGB
import com.google.common.collect.Lists
import net.fabricmc.loader.impl.util.StringUtil
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.client.sounds.SoundManager
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.util.Mth.floor
class BattleMoveSelection(
@@ -94,16 +91,16 @@ class BattleMoveSelection(
open val response: MoveActionResponse get() = MoveActionResponse(move.id, targetPnx)
open val selectable: Boolean get() = !move.disabled
val target: Targetable? get() = targetList?.let { targets ->
val targetPnx: String? get() = targetList?.let { targets ->
return@let when {
targets.isEmpty() -> null
targets.size == 1 -> targets[0]
targets.size == 1 -> targets[0].getPNX()
else -> null // TODO: multi-battles
}
}
val targetPnx: String? get() = target?.getPNX()
fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
val selectConditionOpacity = moveSelection.opacity * if (!selectable) 0.5F else 1F
blitk(
@@ -176,8 +173,6 @@ class BattleMoveSelection(
opacity = moveSelection.opacity,
centered = true
)
drawTooltip(context, mouseX, mouseY)
}
fun isHovered(mouseX: Double, mouseY: Double) = mouseX >= x && mouseX <= x + MOVE_WIDTH && mouseY >= y && mouseY <= y + MOVE_HEIGHT
@@ -187,41 +182,6 @@ class BattleMoveSelection(
moveSelection.playDownSound(Minecraft.getInstance().soundManager)
moveSelection.battleGUI.selectAction(moveSelection.request, response)
}
private fun drawTooltip(context: GuiGraphics, mouseX: Int, mouseY: Int) {
if (!isHovered(mouseX.toDouble(), mouseY.toDouble())) return
val textTooltip: MutableList<MutableComponent> = mutableListOf()
for (descriptionLine in StringUtil.wrapLines(moveTemplate.description.string, 80).split("\n")) {
textTooltip.add(Component.literal(descriptionLine).gray())
}
textTooltip.add(Component.literal(""))
if (moveTemplate.power > 0) textTooltip.add(lang("ui.power").append(String.format(": %d", moveTemplate.power.toInt())))
if (moveTemplate.accuracy > 0) textTooltip.add(lang("ui.accuracy").append(String.format(": %d%%", moveTemplate.accuracy.toInt())))
if (moveTemplate.power > 0 && moveTemplate.target != MoveTarget.self && target is ActiveClientBattlePokemon) {
val species = (target as ActiveClientBattlePokemon).battlePokemon?.species
if (species != null) {
val moveEffectiveness: Double = TypeChart.getMoveEffectiveness(elementalType, listOf(species.primaryType, species.secondaryType))
textTooltip.add(when {
moveEffectiveness == 0.0 -> lang("battle.ui.effectiveness.immunity", moveEffectiveness).gray()
moveEffectiveness < 1.0 -> lang("battle.ui.effectiveness.resistance", moveEffectiveness).gray()
moveEffectiveness > 1.0 -> lang("battle.ui.effectiveness.super_effective", moveEffectiveness).yellow()
else -> lang("battle.ui.effectiveness.normal", moveEffectiveness).white()
})
}
}
context.renderTooltip(
Minecraft.getInstance().font,
Lists.transform(textTooltip, Component::getVisualOrderText),
mouseX,
mouseY
)
}
}
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
@@ -89,7 +89,7 @@ class BattleTargetSelection(
val isAlly = target.isAllied(request.activePokemon)
val teamSize = request.activePokemon.getSidePokemon().count()
val fieldPos = if(isAlly) index % teamSize else teamSize - 1 - (index % teamSize)
val verticalAligned = true
val verticalAligned = false
val x: Float
val y: Float
val arrowDirection: ArrowDirection
@@ -201,7 +201,7 @@ class DialogueScreen(var dialogueDTO: DialogueDTO) : Screen("gui.dialogue".asTra
addRenderableOnly(dialoguePortraitWidget)
if (dialogueDTO.dialogueInput.inputType == DialogueInputDTO.InputType.TEXT) {
//focusOn(dialogueTextInputWidget)
setInitialFocus(dialogueTextInputWidget)
}
dialogueDTO.currentPageDTO.clientActions.flatMap(String::asExpressions).resolve(runtime)
@@ -8,64 +8,18 @@
package com.cobblemon.mod.common.client.net.effect
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.molang.MoLangFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
import com.cobblemon.mod.common.client.particle.ParticleStorm
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import net.minecraft.client.Minecraft
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSnowstormEntityParticlePacket> {
override fun handle(packet: SpawnSnowstormEntityParticlePacket, client: Minecraft) {
val world = Minecraft.getInstance().level ?: return
val effect = BedrockParticleOptionsRepository.getEffect(packet.effectId) ?: return
val entity = world.getEntity(packet.entityId)
if (entity is PosableEntity) {
val state = entity.delegate as PosableState
val locators = packet.locator.firstNotNullOfOrNull { state.getMatchingLocators(it).takeIf { it.isNotEmpty() } } ?: return
val matrixWrappers = locators.mapNotNull { state.locatorStates[it] }
matrixWrappers.forEach { matrixWrapper ->
val particleRuntime = MoLangRuntime().setup().setupClient()
particleRuntime.environment.query.addFunction("entity") { state.runtime.environment.query }
val storm = ParticleStorm(
effect = effect,
matrixWrapper = matrixWrapper,
world = world,
runtime = particleRuntime,
sourceVelocity = { entity.deltaMovement },
sourceAlive = { !entity.isRemoved },
sourceVisible = { !entity.isInvisible },
entity = entity
)
storm.spawn()
}
} else if (entity is LivingEntity) {
val matrixWrapper = MatrixWrapper()
matrixWrapper.updateFunction = { it.updatePosition(entity.position()) }
val particleRuntime = MoLangRuntime().setup().setupClient()
particleRuntime.environment.query.addFunction("entity") { params -> MoLangFunctions.entityFunctions.flatMap { it(entity).map { it.key to it.value } } }
val storm = ParticleStorm(
effect = effect,
matrixWrapper = matrixWrapper,
world = world,
runtime = particleRuntime,
sourceVelocity = { entity.deltaMovement },
sourceAlive = { !entity.isRemoved },
sourceVisible = { !entity.isInvisible },
entity = entity
)
storm.spawn()
}
val entity = world.getEntity(packet.entityId) as? LivingEntity ?: return
ParticleStorm.createAtEntity(world, effect, entity, packet.locator).forEach(ParticleStorm::spawn)
}
}
@@ -11,21 +11,13 @@ package com.cobblemon.mod.common.client.net.effect
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
import com.cobblemon.mod.common.client.particle.ParticleStorm
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import net.minecraft.client.Minecraft
import com.mojang.blaze3d.vertex.PoseStack
object SpawnSnowstormParticleHandler : ClientNetworkPacketHandler<SpawnSnowstormParticlePacket> {
override fun handle(packet: SpawnSnowstormParticlePacket, client: Minecraft) {
val wrapper = MatrixWrapper()
val matrix = PoseStack()
matrix.translate(packet.position.x, packet.position.y, packet.position.z)
// matrix.multiply(YP.rotationDegrees(packet.yawDegrees))
// matrix.multiply(NEGATIVE_X.rotationDegrees(packet.pitchDegrees))
wrapper.updateMatrix(matrix.last().pose())
val world = Minecraft.getInstance().level ?: return
val effect = BedrockParticleOptionsRepository.getEffect(packet.effectId) ?: return
ParticleStorm(effect, wrapper, world).spawn()
ParticleStorm.createAtPosition(world, effect, packet.position).spawn()
}
}
@@ -10,15 +10,20 @@ package com.cobblemon.mod.common.client.particle
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.snowstorm.BedrockParticleOptions
import com.cobblemon.mod.common.api.snowstorm.ParticleEmitterAction
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.client.render.SnowstormParticle
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.particle.SnowstormParticleOptions
import com.cobblemon.mod.common.util.math.geometry.transformDirection
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.Minecraft
import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.client.particle.NoRenderParticle
@@ -26,6 +31,8 @@ import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec3
import kotlin.random.Random
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.level.Level
/**
* An instance of a bedrock particle effect.
@@ -95,6 +102,56 @@ class ParticleStorm(
companion object {
var contextStorm: ParticleStorm? = null
fun createAtPosition(world: ClientLevel, effect: BedrockParticleOptions, position: Vec3): ParticleStorm {
val wrapper = MatrixWrapper()
val matrix = PoseStack()
matrix.translate(position.x, position.y, position.z)
wrapper.updateMatrix(matrix.last().pose())
return ParticleStorm(effect, wrapper, world)
}
/**
* Creates multiple potentially, because in the case of posable entities if multiple locators match, it repeats the effect.
*/
fun createAtEntity(world: ClientLevel, effect: BedrockParticleOptions, entity: LivingEntity, locator: Collection<String> = emptySet()): List<ParticleStorm> {
if (entity is PosableEntity) {
val state = entity.delegate as PosableState
val locators = locator.firstNotNullOfOrNull { state.getMatchingLocators(it).takeIf { it.isNotEmpty() } } ?: return emptyList()
val matrixWrappers = locators.mapNotNull { state.locatorStates[it] }
return matrixWrappers.map { matrixWrapper ->
val particleRuntime = MoLangRuntime().setup().setupClient()
particleRuntime.environment.query.addFunction("entity") { state.runtime.environment.query }
ParticleStorm(
effect = effect,
matrixWrapper = matrixWrapper,
world = world,
runtime = particleRuntime,
sourceVelocity = { entity.deltaMovement },
sourceAlive = { !entity.isRemoved },
sourceVisible = { !entity.isInvisible },
entity = entity
)
}
} else {
val matrixWrapper = MatrixWrapper()
matrixWrapper.updateFunction = { it.updatePosition(entity.position()) }
val particleRuntime = MoLangRuntime().setup().setupClient()
particleRuntime.environment.query.addFunction("entity") { params -> MoLangFunctions.entityFunctions.flatMap { it(entity).map { it.key to it.value } } }
return listOf(
ParticleStorm(
effect = effect,
matrixWrapper = matrixWrapper,
world = world,
runtime = particleRuntime,
sourceVelocity = { entity.deltaMovement },
sourceAlive = { !entity.isRemoved },
sourceVisible = { !entity.isInvisible },
entity = entity
)
)
}
}
}
val particleEffect = SnowstormParticleOptions(effect)
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
@@ -61,7 +62,11 @@ class NoctowlModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, B
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("noctowl", "ground_idle")
WingFlapIdleAnimation(this,
flapFunction = sineFunction(verticalShift = -10F.toRadians(), period = 0.9F, amplitude = 0.8F),
timeVariable = { state, _, _ -> state.animationSeconds },
axis = ModelPartTransformation.Y_AXIS
)
)
)
fly = registerPose(
@@ -70,7 +75,11 @@ class NoctowlModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, B
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("noctowl", "ground_idle")
WingFlapIdleAnimation(this,
flapFunction = sineFunction(verticalShift = -10F.toRadians(), period = 0.9F, amplitude = 0.8F),
timeVariable = { state, _, _ -> state.animationSeconds },
axis = ModelPartTransformation.Y_AXIS
)
)
)
walk = registerPose(
@@ -44,7 +44,7 @@ class LotadModel (root: ModelPart) : PokemonPosableModel(root), QuadrupedFrame {
val wateroffset = -2
override fun registerPoses() {
val blink = quirk { bedrockStateful("charmander", "blink") }
val blink = quirk { bedrockStateful("lotad", "blink") }
standing = registerPose(
poseName = "standing",
@@ -59,6 +59,10 @@ class SimpleQuirk(
private fun applyAnimations(state: PosableState, data: SimpleQuirkData) {
val (primary, stateful) = animations(state).partition { it is PrimaryAnimation }
data.animations.addAll(stateful)
// We hit these to 'start' them (mainly to set the startedSeconds) but we don't need to do that for the primaryAnimation
// because state.addPrimaryAnimation does that for us. We don't technically add these stateful animations to the state
// so if not for this line, nothing would set the start time.
stateful.forEach { it.start(state) }
if (primary.isNotEmpty()) {
val primaryAnimation = primary.first() as PrimaryAnimation
data.primaryAnimation = primaryAnimation
@@ -181,7 +181,7 @@ class CobblemonConfig {
var displayNameForUnknownPokemon = false
@NodeCategory(Category.Pokemon)
var displayEntityLabelsWhenCrouchingOnly = true
var displayEntityLabelsWhenCrouchingOnly = false
@NodeCategory(Category.Spawning)
var shinyRate = 8192F
@@ -14,7 +14,6 @@ import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component
import net.minecraft.network.protocol.Packet
import net.minecraft.network.protocol.game.ClientGamePacketListener
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
@@ -73,8 +72,6 @@ open class CobblemonBoatEntity(entityType: EntityType<out Boat>, world: Level) :
builder.define(TYPE_TRACKED_DATA, CobblemonBoatType.APRICORN.ordinal)
}
override fun getTypeName(): Component = EntityType.BOAT.description
override fun readAdditionalSaveData(nbt: CompoundTag) {
if (nbt.contains(TYPE_KEY, Tag.TAG_STRING.toInt())) {
this.boatType = CobblemonBoatType.valueOf(nbt.getString(TYPE_KEY))
@@ -40,8 +40,6 @@ class CobblemonChestBoatEntity(entityType: EntityType<CobblemonChestBoatEntity>,
this.zo = z
}
private var itemStacks: NonNullList<ItemStack>? = null
private var lootTable: ResourceKey<LootTable>? = null
private var inventory = this.emptyInventory()
private var lootTableId: ResourceKey<LootTable>? = null
private var lootTableSeed = 0L
@@ -54,9 +52,9 @@ class CobblemonChestBoatEntity(entityType: EntityType<CobblemonChestBoatEntity>,
}
}
override fun interact(player: Player, hand: InteractionHand?): InteractionResult {
override fun interact(player: Player, hand: InteractionHand): InteractionResult {
if (!player.isSecondaryUseActive) {
val interactionResult = super.interact(player, hand!!)
val interactionResult = super.interact(player, hand)
if (interactionResult != InteractionResult.PASS) {
return interactionResult
}
@@ -24,6 +24,8 @@ import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.detail.EntitySpawnResult
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
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.text.red
import com.cobblemon.mod.common.client.sound.EntitySoundTracker
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
@@ -180,7 +182,7 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
}
fun chooseAdjustedSpawnBucket(buckets: List<SpawnBucket>, luckOfTheSeaLevel: Int): SpawnBucket {
val baseIncreases = listOf(2.5F, 1.0F, 0.6F) // Base increases for the first three buckets beyond the first
val baseIncreases = listOf(2.5F, 0.5F, 0.2F) // Base increases for the first three buckets beyond the first
val adjustedWeights = buckets.mapIndexed { index, bucket ->
if (index == 0) {
// Placeholder, will be recalculated
@@ -687,7 +689,12 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
)
val result = spawner.run(spawnCause, level() as ServerLevel, position().toBlockPos())
val result = spawner.run(
cause = spawnCause,
world = level() as ServerLevel,
pos = position().toBlockPos(),
influences = listOf(PlayerLevelRangeInfluence(player as ServerPlayer, TYPICAL_VARIATION))
)
if (result == null) {
// This has a chance to fail, if the position has no suitability for a fishing context
@@ -70,6 +70,7 @@ import net.minecraft.world.InteractionResult
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.AgeableMob
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.EntityDimensions
import net.minecraft.world.entity.Pose
import net.minecraft.world.entity.ai.Brain
import net.minecraft.world.entity.ai.attributes.AttributeSupplier
@@ -101,6 +102,8 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
brain = makeBrain(brainDynamic ?: makeEmptyBrainDynamic())
}
}
this.refreshDimensions()
}
val level: Int
@@ -108,6 +111,8 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
var skill: Int? = null // range from 0 - 5
var hitbox: EntityDimensions? = null
var party: NPCPartyStore? = null
var isMovable: Boolean? = null
@@ -342,6 +347,14 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
it.putByteArray(DataKeys.NPC_PLAYER_TEXTURE_TEXTURE, playerTexture.texture)
})
}
val hitbox = hitbox
if (hitbox != null) {
nbt.put(DataKeys.NPC_HITBOX, CompoundTag().also {
it.putFloat(DataKeys.NPC_HITBOX_WIDTH, hitbox.width)
it.putFloat(DataKeys.NPC_HITBOX_HEIGHT, hitbox.height)
it.putBoolean(DataKeys.NPC_HITBOX_FIXED, hitbox.fixed)
})
}
val isMovable = isMovable
if (isMovable != null) {
nbt.putBoolean(DataKeys.NPC_IS_MOVABLE, isMovable)
@@ -361,9 +374,6 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
return nbt
}
override fun hasCustomName() = true
override fun isCustomNameVisible() = true
override fun load(nbt: CompoundTag) {
npc = NPCClasses.getByIdentifier(ResourceLocation.parse(nbt.getString(DataKeys.NPC_CLASS))) ?: NPCClasses.classes.first()
entityData.set(LEVEL, nbt.getInt(DataKeys.NPC_LEVEL).takeIf { it != 0 } ?: 1)
@@ -396,7 +406,17 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
this.isInvulnerable = if (nbt.contains(DataKeys.NPC_IS_INVULNERABLE)) nbt.getBoolean(DataKeys.NPC_IS_INVULNERABLE) else null
this.isLeashable = if (nbt.contains(DataKeys.NPC_IS_LEASHABLE)) nbt.getBoolean(DataKeys.NPC_IS_LEASHABLE) else null
this.allowProjectileHits = if (nbt.contains(DataKeys.NPC_ALLOW_PROJECTILE_HITS)) nbt.getBoolean(DataKeys.NPC_ALLOW_PROJECTILE_HITS) else null
this.hitbox = if (nbt.contains(DataKeys.NPC_HITBOX)) {
val hitboxNBT = nbt.getCompound(DataKeys.NPC_HITBOX)
val width = hitboxNBT.getFloat(DataKeys.NPC_HITBOX_WIDTH)
val height = hitboxNBT.getFloat(DataKeys.NPC_HITBOX_HEIGHT)
val fixed = hitboxNBT.getBoolean(DataKeys.NPC_HITBOX_FIXED)
if (fixed) EntityDimensions.fixed(width, height) else EntityDimensions.scalable(width, height)
} else {
null
}
updateAspects()
}
@@ -426,9 +446,14 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
updateAspects()
}
override fun isPersistenceRequired() = !npc.canDespawn
override fun hasCustomName() = true
override fun getDefaultDimensions(pose: Pose) = npc.hitbox
override fun isCustomNameVisible() = true
override fun isPersistenceRequired(): Boolean {
return super.isPersistenceRequired() || !npc.canDespawn
}
override fun getDimensions(pose: Pose): EntityDimensions = hitbox ?: npc.hitbox
override fun isPushable(): Boolean {
return isMovable ?: npc.isMovable
@@ -261,7 +261,16 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
capturingPokemon = pokemonEntity
entityData.set(HIT_VELOCITY, deltaMovement.normalize())
entityData.set(HIT_TARGET_POSITION, hitResult.location)
attemptCatch(pokemonEntity)
CobblemonEvents.THROWN_POKEBALL_HIT.postThen(
event = ThrownPokeballHitEvent(this, pokemonEntity),
ifSucceeded = {
attemptCatch(pokemonEntity)
},
ifCanceled = {
drop()
return
}
)
return
}
}
@@ -284,19 +293,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
delegate.tick(this)
if (level().isServerSide()) {
capturingPokemon?.let {
if (!it.isInvisible) {
entityData.set(HIT_TARGET_POSITION, it.position())
}
CobblemonEvents.THROWN_POKEBALL_HIT.postThen(
event = ThrownPokeballHitEvent(this, it),
ifSucceeded = {},
ifCanceled = {
drop()
return
}
)
}
if (this.tickCount > 600 && this.capturingPokemon == null) {
this.remove(RemovalReason.DISCARDED)
@@ -47,6 +47,7 @@ import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.SuccessfulBattleStart
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.entity.PlatformType
@@ -78,15 +79,7 @@ import com.cobblemon.mod.common.pokemon.ai.FormPokemonBehaviour
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.feature.StashHandler
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.getBitForByte
import com.cobblemon.mod.common.util.giveOrDropItemStack
import com.cobblemon.mod.common.util.isPokemonEntity
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.playSoundServer
import com.cobblemon.mod.common.util.setBitForByte
import com.cobblemon.mod.common.util.toNbtList
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import com.mojang.serialization.Codec
import java.util.EnumSet
@@ -117,6 +110,8 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.tags.FluidTags
import net.minecraft.util.Mth
import net.minecraft.util.Mth.clamp
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.damagesource.DamageSource
@@ -178,8 +173,10 @@ open class PokemonEntity(
@JvmStatic val FRIENDSHIP = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.INT)
@JvmStatic val FREEZE_FRAME = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.FLOAT)
@JvmStatic val CAUGHT_BALL = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.STRING)
@JvmStatic val EVOLUTION_STARTED = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.BOOLEAN)
const val BATTLE_LOCK = "battle"
const val EVOLUTION_LOCK = "evolving"
fun createAttributes(): AttributeSupplier.Builder = LivingEntity.createLivingAttributes()
.add(Attributes.FOLLOW_RANGE)
@@ -214,6 +211,8 @@ open class PokemonEntity(
/** The player that caused this Pokémon to faint. */
var killer: ServerPlayer? = null
val isEvolving: Boolean
get() = entityData.get(EVOLUTION_STARTED)
var evolutionEntity: GenericBedrockEntity? = null
var ticksLived = 0
@@ -321,11 +320,12 @@ open class PokemonEntity(
builder.define(LABEL_LEVEL, 1)
builder.define(HIDE_LABEL, false)
builder.define(UNBATTLEABLE, false)
builder.define(SPAWN_DIRECTION, level().random.nextFloat() * 360F)
builder.define(SPAWN_DIRECTION, ((level().random.nextFloat() * 360F - 180F) * 1000).toInt() / 1000F)
builder.define(COUNTS_TOWARDS_SPAWN_CAP, true)
builder.define(FRIENDSHIP, 0)
builder.define(FREEZE_FRAME, -1F)
builder.define(CAUGHT_BALL, "")
builder.define(EVOLUTION_STARTED, false)
}
override fun onSyncedDataUpdated(data: EntityDataAccessor<*>) {
@@ -355,6 +355,15 @@ open class PokemonEntity(
busyLocks.remove(BATTLE_LOCK)
}
}
EVOLUTION_STARTED -> {
if (isEvolving) {
busyLocks.remove(EVOLUTION_LOCK)
busyLocks.add(EVOLUTION_LOCK)
} else {
busyLocks.remove(EVOLUTION_LOCK)
}
}
}
}
@@ -387,16 +396,28 @@ open class PokemonEntity(
}
override fun tick() {
this.clampRotationsAsNecessary()
/* Addresses watchdog hanging that is completely bloody inexplicable. */
yBodyRot = Mth.wrapDegrees(yBodyRot)
yBodyRotO = Mth.wrapDegrees(yBodyRotO)
yRot = Mth.wrapDegrees(yRot)
yRotO = Mth.wrapDegrees(yRotO)
xRot = Mth.wrapDegrees(xRot)
xRotO = Mth.wrapDegrees(xRotO)
yHeadRot = Mth.wrapDegrees(yHeadRot)
yHeadRotO = Mth.wrapDegrees(yHeadRotO)
/* I'm sure it's not even us but something altering the logic of the loops in LivingEntity */
super.tick()
if (isBattling) {
// Deploy a platform if a non-wild Pokemon is touching water but not underwater.
// This can't be done in the BattleMovementGoal as the sleep goal will override it.
if (ticksLived > 5 && platform == PlatformType.NONE
&& this.ownerUUID != null
// Clients also don't seem to have correct info about behavior
if (!level().isClientSide && ticksLived > 5 && platform == PlatformType.NONE
&& ownerUUID != null
&& isInWater && !isUnderWater
&& !exposedForm.behaviour.moving.swim.canBreatheUnderwater && !exposedForm.behaviour.moving.swim.canWalkOnWater) {
&& !exposedForm.behaviour.moving.swim.canBreatheUnderwater && !exposedForm.behaviour.moving.swim.canWalkOnWater
&& !getBehaviourFlag(PokemonBehaviourFlag.FLYING)) {
platform = PlatformType.getPlatformTypeForPokemon((exposedForm))
}
} else {
@@ -418,14 +439,11 @@ open class PokemonEntity(
}
delegate.tick(this)
ticksLived++
if (this.ticksLived % 20 == 0) {
//this.updateEyeHeight()
}
if (ticksLived <= 20) {
clearRestriction()
val spawnDirection = entityData.get(SPAWN_DIRECTION).coerceIn(-360F, 360F).takeIf { it.isFinite() } ?: 0F
yBodyRot = spawnDirection
// val spawnDirection = entityData.get(SPAWN_DIRECTION).takeIf { it.isFinite() } ?: 0F
// yBodyRot = (spawnDirection * 1000F).toInt() / 1000F
}
if (this.tethering != null && !this.tethering!!.box.contains(this.x, this.y, this.z)) {
@@ -973,6 +991,8 @@ open class PokemonEntity(
return false
} else if (health <= 0F || isDeadOrDying) {
return false
} else if (player.isPartyBusy()) {
return false
}
return true
@@ -1428,9 +1448,8 @@ open class PokemonEntity(
if (!canBattle(player)) {
return false
}
var isSuccessful = false
BattleBuilder.pve(player, this).ifSuccessful { isSuccessful = true }
return isSuccessful
val lead = player.party().firstOrNull { it.entity != null }?.uuid
return BattleBuilder.pve(player, this, lead) is SuccessfulBattleStart
}
/**
@@ -1572,24 +1591,5 @@ open class PokemonEntity(
override fun resolveEntityScan(): LivingEntity {
return this
}
}
private fun clampRotationsAsNecessary() {
// this.yRotO = this.clampRotationIfNecessary("yRot0", this.yRotO)
// this.yRot = this.clampRotationIfNecessary("yRot", this.yRot)
// this.xRotO = this.clampRotationIfNecessary("xRot0", this.xRotO)
// this.xRot = this.clampRotationIfNecessary("xRot", this.xRot)
// this.yHeadRot = this.clampRotationIfNecessary("yHeadRot", this.yHeadRot)
// this.yBodyRot = this.clampRotationIfNecessary("yBodyRot", this.yBodyRot)
// this.yHeadRotO = this.clampRotationIfNecessary("yHeadRotO", this.yHeadRotO)
// this.yBodyRotO = this.clampRotationIfNecessary("yBodyRotO", this.yBodyRotO)
}
private fun clampRotationIfNecessary(name: String, input: Float) : Float {
if (!(input >= -9999F && input <= 9999F)) {
Cobblemon.LOGGER.warn("Invalid entity rotation: $name $input (${this.pokemon.species.resourceIdentifier})")
return Math.clamp(input, -180F, 180F)
}
return input
}
}
@@ -107,8 +107,7 @@ class PokemonServerDelegate : PokemonSideDelegate {
val trackedAspects = mock?.aspects ?: entity.pokemon.aspects
val trackedBall = mock?.pokeball ?: entity.pokemon.caughtBall.name.toString()
//used getOwnerPlayer().uuid instead of getOwnerUUID() to avoid a potential NPE
entity.ownerUUID = entity.pokemon.getOwnerPlayer()?.uuid
entity.ownerUUID = entity.pokemon.getOwnerUUID()
entity.entityData.set(PokemonEntity.SPECIES, trackedSpecies)
if (entity.entityData.get(PokemonEntity.NICKNAME) != trackedNickname) {
entity.entityData.set(PokemonEntity.NICKNAME, trackedNickname)
@@ -50,7 +50,7 @@ class PokemonInBattleMovementGoal(val entity: PokemonEntity, val range: Int) : G
entity.navigation.moveTo(battlePos!!.x, battlePos!!.y, battlePos!!.z, 1.0)
hasMovedToPos = true
}
if (entity.ticksLived > 1 && !entity.onGround() && !entity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) {
if (entity.ticksLived > 1 && !entity.getBehaviourFlag(PokemonBehaviourFlag.FLYING) && entity.navigation.isAirborne(entity.level(), entity.blockPosition())) {
// Let flyers fly in battle if they're in the air
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
}
@@ -19,7 +19,8 @@ object FlowHandler {
fun setup() {
CobblemonEvents.POKEMON_CAPTURED.subscribe { CobblemonFlows.run(cobblemonResource("pokemon_captured"), it.context) }
CobblemonEvents.BATTLE_VICTORY.subscribe { CobblemonFlows.run(cobblemonResource("battle_victory"), it.context) }
CobblemonEvents.POKEDEX_DATA_CHANGED.subscribe { CobblemonFlows.run(cobblemonResource("pokedex_data_changed"), it.context) }
CobblemonEvents.POKEDEX_DATA_CHANGED_PRE.subscribe { CobblemonFlows.run(cobblemonResource("pokedex_data_changed_pre"), it.getContext(), it) }
CobblemonEvents.POKEDEX_DATA_CHANGED_POST.subscribe { CobblemonFlows.run(cobblemonResource("pokedex_data_changed_post"), it.getContext()) }
}
}
@@ -86,7 +86,8 @@ class PokedexItem(val type: PokedexType): CobblemonItem(Item.Properties().stacks
remainingUseTicks: Int
) {
// Check if the player is interacting with a Pokémon
val entity = world.getEntities(user, AABB.ofSize(user.position(), 11.0, 11.0, 11.0))
val range = if (user is Player) user.entityInteractionRange() else 5.0
val entity = world.getEntities(user, AABB.ofSize(user.position(), range, range, range))
.filter { user.isLookingAt(it, stepDistance = 0.1F) }
.minByOrNull { it.distanceTo(user) } as? PokemonEntity?
@@ -13,7 +13,4 @@ import net.minecraft.core.particles.ParticleOptions
class SnowstormParticleOptions(val effect: BedrockParticleOptions) : ParticleOptions {
override fun getType() = CobblemonParticles.SNOWSTORM_PARTICLE_TYPE
companion object {
}
}
@@ -153,6 +153,7 @@ import net.minecraft.world.level.block.SweetBerryBushBlock
import net.minecraft.world.level.block.WitherRoseBlock
import net.minecraft.world.phys.Vec3
import kotlin.math.*
import net.minecraft.util.Mth
enum class OriginalTrainerType : StringRepresentable {
NONE, PLAYER, NPC;
@@ -648,7 +649,7 @@ open class Pokemon : ShowdownIdentifiable {
if (!spawnYaw.isFinite()) {
spawnYaw = 0.0
}
it.entityData.set(PokemonEntity.SPAWN_DIRECTION, spawnYaw.toFloat())
it.entityData.set(PokemonEntity.SPAWN_DIRECTION, Mth.wrapDegrees(spawnYaw.toFloat()))
}
if (owner != null) {
level.playSoundServer(owner.position(), CobblemonSounds.POKE_BALL_THROW, volume = 0.6F)
@@ -983,12 +984,12 @@ open class Pokemon : ShowdownIdentifiable {
fun clone(newUUID: Boolean = true): Pokemon {
// NBT is faster, ops type doesn't really matter
val encoded = CODEC.encodeStart(NbtOps.INSTANCE, this).orThrow
if (newUUID) {
NbtOps.INSTANCE.set(encoded, DataKeys.POKEMON_UUID, StringTag.valueOf(UUID.randomUUID().toString()))
NbtOps.INSTANCE.remove(encoded, DataKeys.TETHERING_ID)
}
val result = CODEC.decode(NbtOps.INSTANCE, encoded).orThrow.first
result.isClient = this.isClient
if (newUUID) {
result.uuid = UUID.randomUUID()
result.tetheringId = null
}
return result
}
@@ -25,7 +25,7 @@ object NoAIProperty : CustomPokemonPropertyType<BooleanProperty> {
key = keys.first(),
value = value,
pokemonApplicator = { _, _ -> },
entityApplicator = { pokemonEntity, noAI -> pokemonEntity.isNoAi = true },
entityApplicator = { pokemonEntity, noAI -> pokemonEntity.isNoAi = value },
pokemonMatcher = { _, _ -> false },
entityMatcher = { pokemonEntity, noAI -> pokemonEntity.isNoAi == noAI }
)
@@ -219,6 +219,10 @@ object DataKeys {
const val NPC_IS_INVULNERABLE = "IsInvulnerable"
const val NPC_IS_LEASHABLE = "IsLeashable"
const val NPC_ALLOW_PROJECTILE_HITS = "AllowProjectileHits"
const val NPC_HITBOX = "Hitbox"
const val NPC_HITBOX_WIDTH = "Width"
const val NPC_HITBOX_HEIGHT = "Height"
const val NPC_HITBOX_FIXED = "Fixed"
// PokemonProperties
const val ELEMENTAL_TYPE = "ElementalType"
@@ -174,6 +174,7 @@ fun List<Expression>.resolveInt(runtime: MoLangRuntime, context: Map<String, MoV
fun List<Expression>.resolveBoolean(runtime: MoLangRuntime, context: Map<String, MoValue> = runtime.contextOrEmpty) = resolveDouble(runtime, context) == 1.0
fun List<Expression>.resolveObject(runtime: MoLangRuntime, context: Map<String, MoValue> = runtime.contextOrEmpty) = resolve(runtime, context) as ObjectValue<*>
fun <T : MoValue> MoParams.getOrNull(index: Int) = if (params.size > index) get<T>(index) else null
fun MoParams.getStringOrNull(index: Int) = if (params.size > index) getString(index) else null
fun MoParams.getDoubleOrNull(index: Int) = if (params.size > index) getDouble(index) else null
fun MoParams.getBooleanOrNull(index: Int) = if (params.size > index) getDouble(index) == 1.0 else null
@@ -19,6 +19,8 @@ import com.cobblemon.mod.common.api.reactive.Observable.Companion.filter
import com.cobblemon.mod.common.api.reactive.Observable.Companion.takeFirst
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.TeamManager
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.item.PokedexItem
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -169,11 +171,14 @@ fun <T : Entity> Player.traceEntityCollision(
AABB(startPos.subtract(maxDistanceVector), startPos.add(maxDistanceVector)),
{ entityClass.isInstance(it) }
)
while (step <= maxDistance) {
val location = startPos.add(direction.scale(step.toDouble()))
step += stepDistance
val collided = entities.filter { ignoreEntity != it && location in it.boundingBox }.filter { entityClass.isInstance(it) }
val collided = entities.filter {
ignoreEntity != it && location in it.boundingBox && entityClass.isInstance(it) && !it.isSpectator
}
if (collided.isNotEmpty()) {
if(collideBlock != null && level().clip(ClipContext(startPos, location, ClipContext.Block.COLLIDER, collideBlock, this)).type == HitResult.Type.BLOCK) {
@@ -408,6 +413,14 @@ fun Player.giveOrDropItemStack(stack: ItemStack, playSound: Boolean = true) {
/** Retrieves the battle theme associated with this player, or the default PVP theme if null. */
fun ServerPlayer.getBattleTheme() = Cobblemon.playerDataManager.getGenericData(this).battleTheme?.let { BuiltInRegistries.SOUND_EVENT.get(it) } ?: CobblemonSounds.PVP_BATTLE
/** Checks if any [PokemonEntity]s belonging to a player's party has any busy locks. */
fun Player.isPartyBusy() =
if (this.level().isClientSide)
CobblemonClient.storage.myParty.find { it?.entity?.isBusy == true } != null
else
Cobblemon.storage.getParty(this.uuid, this.registryAccess()).find { it?.entity?.isBusy == true } != null
fun Player.isUsingPokedex() = isUsingItem &&
((mainHandItem.item is PokedexItem && usedItemHand == InteractionHand.MAIN_HAND) ||
(offhandItem.item is PokedexItem && usedItemHand == InteractionHand.OFF_HAND))
(offhandItem.item is PokedexItem && usedItemHand == InteractionHand.OFF_HAND))
@@ -2,7 +2,7 @@
"format_version": "1.8.0",
"animations": {
"animation.evolution.evolution": {
"animation_length": 18.45833,
"animation_length": 12.0,
"bones": {
"root_part": {
"rotation": {
@@ -85,7 +85,7 @@
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 15
"active_time": 12
},
"minecraft:emitter_lifetime_events": {
"creation_event": "event_sparkle",
@@ -0,0 +1,80 @@
{
"format_version": "1.8.0",
"animations": {
"animation.delibird.ground_idle": {
"loop": true,
"bones": {
"arm_left": {
"rotation": [0, 0, 37.5]
},
"arm_left2": {
"rotation": [0, 0, 17.5]
},
"arm_left3": {
"rotation": [0, 0, 35]
},
"arm_right": {
"rotation": [12.56853, 12.27659, -43.64293]
},
"arm_right2": {
"rotation": [0, -15, 0]
},
"arm_right3": {
"rotation": [0, -10, 0]
},
"head": {
"rotation": [0, 0, 0]
},
"tail3": {
"rotation": [0, 0, -20]
},
"tail4": {
"rotation": [-6.51543, 39.8173, -4.18273]
},
"leg_left": {
"rotation": [0, -20, 0]
},
"foot_left": {
"rotation": [0, -17.5, 0]
},
"leg_right": {
"rotation": [0, 15, 0]
},
"foot_right": {
"rotation": [0, 22.5, 0]
},
"tail5": {
"rotation": [0, 30, -12.5]
},
"tail6": {
"rotation": [5.082, 12.45269, 1.96903]
},
"tail7": {
"rotation": [7.62353, 7.24305, 1.95155]
},
"tail_end": {
"rotation": [27.5, 0, 0]
}
}
},
"animation.delibird.blink": {
"animation_length": 0.1667,
"bones": {
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
}
}
}
}
}
}
@@ -11,7 +11,7 @@
"rotation": [37.5, 10, 0.00001]
},
"neck2": {
"rotation": [-32.75616, -8.17884, 5.42386]
"rotation": ["-32.7562+Math.cos((query.anim_time-0.6) * 90 * 1) * 4", -8.17884, 5.42386]
},
"neck3": {
"rotation": [-17.5, 0, 0]
@@ -20,7 +20,7 @@
"rotation": [-10, 0, 0]
},
"head_angle": {
"rotation": [27.5, 0, 0]
"rotation": ["27.5+Math.cos((query.anim_time-0.8) * 90 * 1) * -6", 0, 0]
},
"ear_left": {
"rotation": [0, 0, 7.5]
@@ -47,7 +47,7 @@
"rotation": [29.8359, 0.59944, -31.49325]
},
"segment3": {
"rotation": [0, 0, 42.5]
"rotation": [0, 0, "42.5+Math.cos((query.anim_time) * 90 * 1) * 1"]
},
"segment4": {
"rotation": [-12.5, 0, 40]
@@ -59,13 +59,13 @@
"rotation": [27.81308, -5.7287, 46.31672]
},
"segment7": {
"rotation": [24.15616, 7.47099, 40.01878]
"rotation": ["24.1562+Math.cos((query.anim_time-0.2) * 90 * 1) * -4", "7.471+Math.cos((query.anim_time-0.6) * 90 * 1) * -4", 40.01878]
},
"segment8": {
"rotation": [-10, 0, 30]
},
"segment9": {
"rotation": [-10, 0, 22.5]
"rotation": ["-10+Math.cos((query.anim_time-1) * 90 * 1) * -4", 0, 22.5]
},
"neck_leaves": {
"rotation": [-2.5, 0, 0]
@@ -133,10 +133,10 @@
"position": [0, -3, "-13+Math.cos((query.anim_time) * 90 * 2) * 1"]
},
"neck": {
"rotation": [17.5, 0, 0]
"rotation": [10, 0, 0]
},
"neck2": {
"rotation": [-35, 0, 0]
"rotation": ["-35+math.cos((query.anim_time-0.3) * 90 * 2) * +12.5", 0, 0]
},
"arm_left": {
"rotation": [24.51604, -45.05075, 57.20219]
@@ -157,7 +157,7 @@
"rotation": [0, 0, -52.5]
},
"neck3": {
"rotation": [-2.5, 0, 0]
"rotation": ["-2.5+Math.cos((query.anim_time-0.3) * 90 * 2) * -5", 0, 0]
},
"neck_leaves": {
"rotation": [-7.5, 0, 0]
@@ -166,7 +166,7 @@
"rotation": [20, 0, 0]
},
"head_angle": {
"rotation": [17.5, 0, 0]
"rotation": ["12.5+Math.cos((query.anim_time-0.5) * 90 * 2) * 5", 0, 0]
},
"ear_left": {
"rotation": [-5, 0, 7.5]
@@ -215,6 +215,12 @@
},
"segment9": {
"rotation": [0, 0, "math.sin(q.anim_time*90*4-460)*5"]
},
"neck_leave_left2_rotation": {
"rotation": ["4+Math.cos((query.anim_time-0.3) * 90 * 2) * -5", 0, 0]
},
"neck_leave_right2_rotation": {
"rotation": ["4+Math.cos((query.anim_time-0.3) * 90 * 2) * -5", 0, 0]
}
}
},
@@ -4,36 +4,112 @@
"animation.braixen.ground_idle": {
"loop": true,
"bones": {
"torso": {
"rotation": [2.5, 0, 0]
"torso_bottom": {
"rotation": ["-math.sin(q.anim_time*90*2.5-45)*0.75", 0, 0]
},
"neck": {
"rotation": ["10-math.sin(q.anim_time*90*2.5)*2", 0, 0]
},
"head": {
"rotation": ["2.5+math.sin(q.anim_time*90*2.5+45)*2", 0, 0]
},
"ear_ruff_right": {
"rotation": [0, 5, "-1-math.sin(q.anim_time*90*2.5+45)*1"]
},
"ear_ruff_right2": {
"rotation": [0, 10, "-math.sin(q.anim_time*90*2.5)*1"]
},
"ear_ruff_right3": {
"rotation": [0, 10, "-math.sin(q.anim_time*90*2.5-45)*1"]
},
"ear_ruff_left": {
"rotation": [0, -2.5, "1+math.sin(q.anim_time*90*2.5+45)*1"]
},
"ear_ruff_left2": {
"rotation": [0, -10, "math.sin(q.anim_time*90*2.5)*1"]
},
"ear_ruff_left3": {
"rotation": [0, -10, "math.sin(q.anim_time*90*2.5-45)*1"]
},
"arm_right": {
"rotation": [-1.56101, "12.3977-math.sin(q.anim_time*90*2.5+45)", -55.15982]
},
"arm_right2": {
"rotation": [-3.88714, -27.24513, 8.44236]
},
"arm_left": {
"rotation": [-1.465, "-12.404+math.sin(q.anim_time*90*2.5+45)*2", 55.14094]
},
"arm_left2": {
"rotation": [-6.31274, 31.94715, -11.80868]
},
"tail": {
"rotation": ["5+math.sin(q.anim_time*90*2.5)*2", "math.sin(q.anim_time*90*1.25-90)*4", "math.sin(q.anim_time*90*1.25-90)*2"],
"position": [0, 0, 0.5]
},
"stick_tail": {
"rotation": [0, 0, "-math.sin(q.anim_time*90*1.25-45)*4"]
},
"tail2": {
"rotation": [0, 0, "math.sin(q.anim_time*90*1.25-45)*4"]
},
"tail3": {
"rotation": ["math.sin(q.anim_time*90*2.5-90)*2", 0, 0]
},
"tail4": {
"rotation": ["math.sin(q.anim_time*90*2.5-135)*2", 0, 0]
},
"finger_index_right": {
"rotation": [0, 0, -15]
},
"finger_middle_right": {
"rotation": [0, 0, -10]
},
"finger_ring_right": {
"rotation": [0, 0, -5]
},
"finger_index_left": {
"rotation": [0, 0, 15]
},
"finger_middle_left": {
"rotation": [0, 0, 10]
},
"finger_ring_left": {
"rotation": [0, 0, 5]
},
"waist": {
"rotation": [-5, 0, 0]
},
"chest": {
"rotation": [2.5, 0, 0]
},
"arm_left": {
"rotation": [0, -17.5, 57.5]
},
"arm_left2": {
"rotation": [-8.89674, 26.12797, -19.56838]
},
"hand_left": {
"rotation": [0, 0, -15]
"rotation": [0, 0, -7.5]
},
"neck": {
"rotation": [-5, 0, 0]
"finger_front_left": {
"rotation": [0, 0, 25]
},
"head": {
"rotation": [12.5, 0, 0]
"finger_back_left": {
"rotation": [0, 0, 22.5]
},
"tail": {
"hand_right": {
"rotation": [0, 0, 7.5]
},
"finger_front_right": {
"rotation": [0, 0, -25]
},
"finger_back_right": {
"rotation": [0, 0, -22.5]
},
"stick_hand": {
"scale": 0
},
"ear_ruff_shock_left": {
"scale": 0
},
"ear_ruff_shock_right": {
"scale": 0
},
"skirt_front2": {
"rotation": [5, 0, 0]
},
"stick_tail": {
"rotation": [-10, 0, 0]
},
"leg_left": {
"rotation": [0.88045, -9.96156, -5.07673]
},
@@ -49,77 +125,8 @@
"leg_right3": {
"rotation": [0.00039, 5.00185, -5.99069]
},
"finger_front_left": {
"rotation": [9.99527, 9.84653, 30.20756]
},
"finger_back_left": {
"rotation": [-4.26175, -9.05478, 25.33761]
},
"finger_middle_left": {
"rotation": [0, 0, 27.5]
},
"arm_right": {
"rotation": [0, 17.5, -57.5]
},
"arm_right2": {
"rotation": [-8.89674, -26.12797, 19.56838]
},
"hand_right": {
"rotation": [0, 0, 15]
},
"finger_front_right": {
"rotation": [9.99527, -9.84653, -30.20756]
},
"finger_middle_right": {
"rotation": [0, 0, -27.5]
},
"finger_back_right": {
"rotation": [-4.26175, 9.05478, -25.33761]
},
"ear_ruff_left2": {
"rotation": [0, -7.5, 0]
},
"ear_ruff_left3": {
"rotation": [0, -7.5, 0]
},
"ear_ruff_left4": {
"rotation": [0, -7.5, 0]
},
"skirt_front2": {
"rotation": [-2.5, 0, 0]
},
"foot_right": {
"rotation": [1, 0, 0]
},
"ear_ruff_left": {
"rotation": [0, -7.5, 0]
},
"ear_ruff_right": {
"rotation": [0, 7.5, 0]
},
"ear_ruff_right2": {
"rotation": [0, 7.5, 0]
},
"ear_ruff_right3": {
"rotation": [0, 7.5, 0]
},
"ear_ruff_right4": {
"rotation": [0, 7.5, 0]
},
"stick_hand": {
"scale": 0
},
"skirt_front_left": {
"rotation": [0, 0, 10]
},
"skirt_front_right": {
"rotation": [0, 0, -10]
},
"ear_ruff_shock_left": {
"scale": 0
},
"ear_ruff_shock_right": {
"scale": 0
}
}
},
@@ -267,6 +274,141 @@
}
}
},
"animation.braixen.ground_walk": {
"loop": true,
"bones": {
"torso_bottom": {
"rotation": ["2.5-math.sin(q.anim_time*90*10-45)*1", 0, 0]
},
"neck": {
"rotation": ["10-math.sin(q.anim_time*90*10)*2", "-math.sin(q.anim_time*90*5)*5", 0]
},
"head": {
"rotation": ["-17.5+math.sin(q.anim_time*90*10+45)*2", 0, 0]
},
"arm_right": {
"rotation": [0, "0+math.sin(q.anim_time*90*5+45)*10", "-40+math.abs(math.sin(q.anim_time*90*5)*10)"]
},
"arm_right2": {
"rotation": [0, "-20+math.sin(q.anim_time*90*5)*10", 25]
},
"arm_left": {
"rotation": [0, "0+math.sin(q.anim_time*90*5+45)*10", "40-math.abs(math.sin(q.anim_time*90*5)*10)"]
},
"arm_left2": {
"rotation": [0, "20+math.sin(q.anim_time*90*5)*10", -25]
},
"tail": {
"rotation": ["10+math.sin(q.anim_time*90*10)*2", "math.sin(q.anim_time*90*5-90)*8", "math.sin(q.anim_time*90*5-90)*2"],
"position": [0, 0, 0.5]
},
"stick_tail": {
"rotation": [0, 0, "-math.sin(q.anim_time*90*5-45)*6"]
},
"tail2": {
"rotation": [0, 0, "math.sin(q.anim_time*90*5-45)*8"]
},
"tail3": {
"rotation": ["math.sin(q.anim_time*90*10-90)*4", 0, 0]
},
"tail4": {
"rotation": ["math.sin(q.anim_time*90*10-135)*4", 0, 0]
},
"body": {
"rotation": [10, 0, 0],
"position": [0, "math.abs(math.sin(q.anim_time*90*5-15)*1)", 2]
},
"torso_top": {
"rotation": ["-math.sin(q.anim_time*90*10)*0.5", "math.sin(q.anim_time*90*5)*2", 0]
},
"chest": {
"rotation": [0, "math.sin(q.anim_time*90*5)*4", 0]
},
"ear_right_main": {
"rotation": [0, 17.5, 0]
},
"ear_ruff_right": {
"rotation": [0, 0, "-math.sin(q.anim_time*90*10+45)*2"]
},
"ear_ruff_right2": {
"rotation": [0, 22.5, "-math.sin(q.anim_time*90*10)*2"]
},
"ear_ruff_right3": {
"rotation": [0, 10, "-math.sin(q.anim_time*90*10-45)*2"]
},
"ear_left_main": {
"rotation": [0, -17.5, 0]
},
"ear_ruff_left": {
"rotation": [0, 0, "math.sin(q.anim_time*90*10+45)*2"]
},
"ear_ruff_left2": {
"rotation": [0, -20, "math.sin(q.anim_time*90*10)*2"]
},
"ear_ruff_left3": {
"rotation": [0, -10, "math.sin(q.anim_time*90*10-45)*2"]
},
"leg_right": {
"rotation": ["-math.sin(q.anim_time*90*5-90)*15", 0, 0],
"position": [0, "math.clamp(math.sin(q.anim_time*90*5+90*0)*1.5,0,180)", 0]
},
"leg_right2": {
"rotation": ["-math.sin(q.anim_time*90*5-135)*15", 0, 0]
},
"leg_right3": {
"rotation": ["math.clamp(math.sin(q.anim_time*90*5-180)*25,-180,5)", 0, 0]
},
"leg_right4": {
"rotation": ["-math.clamp(math.sin(q.anim_time*90*5-180)*25,-90,0)", 0, 0]
},
"leg_left": {
"rotation": ["math.sin(q.anim_time*90*5-90)*15", 0, 0],
"position": [0, "math.clamp(-math.sin(q.anim_time*90*5+90*0)*1.5,0,180)", 0]
},
"leg_left2": {
"rotation": ["math.sin(q.anim_time*90*5-135)*15", 0, 0]
},
"leg_left3": {
"rotation": ["-math.clamp(math.sin(q.anim_time*90*5-180)*25,-5,180)", 0, 0]
},
"leg_left4": {
"rotation": ["math.clamp(math.sin(q.anim_time*90*5-180)*25,0,90)", 0, 0]
},
"hand_left": {
"rotation": [0, 0, -5]
},
"finger_middle_left": {
"rotation": [0, 0, 7.5]
},
"finger_back_left": {
"rotation": [0, 0, 22.5]
},
"hand_right": {
"rotation": [0, 0, 5]
},
"finger_middle_right": {
"rotation": [0, 0, -7.5]
},
"finger_back_right": {
"rotation": [0, 0, -22.5]
},
"stick_hand": {
"scale": 0
},
"ear_ruff_shock_left": {
"scale": 0
},
"ear_ruff_left4": {
"rotation": [0, 12.5, 0]
},
"ear_ruff_shock_right": {
"scale": 0
},
"ear_ruff_right4": {
"rotation": [0, -12.5, 0]
}
}
},
"animation.braixen.blink": {
"animation_length": 0.1667,
"bones": {
@@ -286,6 +428,52 @@
}
}
},
"animation.braixen.cry": {
"animation_length": 1,
"bones": {
"head": {
"rotation": {
"0.0": [0, 0, 0],
"0.0417": [-2.05, 0, 0],
"0.0833": [-2.7, 0, 0],
"0.1667": [4, 0, 0],
"0.2083": [3.72, 0, 0],
"0.375": [-2.38, 0, 0],
"0.4167": [-2.7, 0, 0],
"0.5": [-2.4, 0, 0],
"0.6667": [-0.3, 0, 0],
"0.75": [0, 0, 0]
}
},
"jaw": {
"rotation": {
"0.0": [0, 0, 0],
"0.0417": [27.2, 0, 0],
"0.0833": [30, 0, 0],
"0.1667": [19, 0, 0],
"0.2083": [17.65, 0, 0],
"0.3333": [57.56, 0, 0],
"0.375": [60, 0, 0],
"0.4167": [56.99, 0, 0],
"0.7083": [4.23, 0, 0],
"0.7917": [0, 0, 0]
}
},
"fangs": {
"position": {
"0.0": [0, 0, 0],
"0.0417": [0, -0.5, 0],
"0.625": [0, -0.5, 0],
"0.6667": [0, 0, 0]
}
}
},
"sound_effects": {
"0.0": {
"effect": "pokemon.braixen.cry"
}
}
},
"animation.braixen.surprise_hair": {
"loop": true,
"bones": {
@@ -402,7 +590,7 @@
}
}
},
"animation.braixen.recoil": {
"animation.braixen.hurt": {
"loop": true,
"bones": {
"eyelid_recoil_left": {
@@ -412,154 +600,6 @@
"position": [-0.1, 0, -0.1]
}
}
},
"animation.braixen.ground_walk_old": {
"loop": true,
"bones": {
"torso_bottom": {
"rotation": ["2.5-math.sin(q.anim_time*90*10-45)*1", 0, 0]
},
"neck": {
"rotation": ["10-math.sin(q.anim_time*90*10)*2", "-math.sin(q.anim_time*90*5)*5", 0]
},
"head": {
"rotation": ["-17.5+math.sin(q.anim_time*90*10+45)*2", 0, 0]
},
"arm_right": {
"rotation": [0, "0+math.sin(q.anim_time*90*5+45)*10", "-40+math.abs(math.sin(q.anim_time*90*5)*10)"]
},
"arm_right2": {
"rotation": [0, "-20+math.sin(q.anim_time*90*5)*10", 25]
},
"arm_left": {
"rotation": [0, "0+math.sin(q.anim_time*90*5+45)*10", "40-math.abs(math.sin(q.anim_time*90*5)*10)"]
},
"arm_left2": {
"rotation": [0, "20+math.sin(q.anim_time*90*5)*10", -25]
},
"tail": {
"rotation": ["10+math.sin(q.anim_time*90*10)*2", "math.sin(q.anim_time*90*5-90)*8", "math.sin(q.anim_time*90*5-90)*2"],
"position": [0, 0, 0.5]
},
"stick_tail": {
"rotation": [0, 0, "-math.sin(q.anim_time*90*5-45)*6"]
},
"tail2": {
"rotation": [0, 0, "math.sin(q.anim_time*90*5-45)*8"]
},
"tail3": {
"rotation": ["math.sin(q.anim_time*90*10-90)*4", 0, 0]
},
"tail4": {
"rotation": ["math.sin(q.anim_time*90*10-135)*4", 0, 0]
},
"body": {
"rotation": [10, 0, 0],
"position": [0, "0.5+math.abs(math.sin(q.anim_time*90*5-45)*1)", 2]
},
"torso_top": {
"rotation": ["-math.sin(q.anim_time*90*10)*0.5", "math.sin(q.anim_time*90*5)*2", 0]
},
"chest": {
"rotation": [0, "math.sin(q.anim_time*90*5)*4", 0]
},
"ear_right_main": {
"rotation": [0, 17.5, 0]
},
"ear_ruff_right": {
"rotation": [0, 0, "-math.sin(q.anim_time*90*10+45)*2"]
},
"ear_ruff_right2": {
"rotation": [0, 0, "-math.sin(q.anim_time*90*10)*2"]
},
"ear_ruff_right3": {
"rotation": [0, 0, "-math.sin(q.anim_time*90*10-45)*2"]
},
"ear_left_main": {
"rotation": [0, -17.5, 0]
},
"ear_ruff_left": {
"rotation": [0, 0, "math.sin(q.anim_time*90*10+45)*2"]
},
"ear_ruff_left2": {
"rotation": [0, 0, "math.sin(q.anim_time*90*10)*2"]
},
"ear_ruff_left3": {
"rotation": [0, 0, "math.sin(q.anim_time*90*10-45)*2"]
},
"leg_right": {
"rotation": ["-math.sin(q.anim_time*90*5-90)*15", 0, 0],
"position": [0, "math.clamp(math.sin(q.anim_time*90*5+90*0)*1.5,0,180)", 0]
},
"leg_right2": {
"rotation": ["-math.sin(q.anim_time*90*5-135)*15", 0, 0]
},
"leg_right3": {
"rotation": ["math.clamp(math.sin(q.anim_time*90*5-180)*25,-180,5)", 0, 0]
},
"leg_right4": {
"rotation": ["-math.clamp(math.sin(q.anim_time*90*5-180)*25,-90,0)", 0, 0]
},
"leg_left": {
"rotation": ["math.sin(q.anim_time*90*5-90)*15", 0, 0],
"position": [0, "math.clamp(-math.sin(q.anim_time*90*5+90*0)*1.5,0,180)", 0]
},
"leg_left2": {
"rotation": ["math.sin(q.anim_time*90*5-135)*15", 0, 0]
},
"leg_left3": {
"rotation": ["-math.clamp(math.sin(q.anim_time*90*5-180)*25,-5,180)", 0, 0]
},
"leg_left4": {
"rotation": ["math.clamp(math.sin(q.anim_time*90*5-180)*25,0,90)", 0, 0]
}
}
},
"animation.braixen.cry": {
"animation_length": 1,
"bones": {
"head": {
"rotation": {
"0.0": [0, 0, 0],
"0.0417": [-2.05, 0, 0],
"0.0833": [-2.7, 0, 0],
"0.1667": [4, 0, 0],
"0.2083": [3.72, 0, 0],
"0.375": [-2.38, 0, 0],
"0.4167": [-2.7, 0, 0],
"0.5": [-2.4, 0, 0],
"0.6667": [-0.3, 0, 0],
"0.75": [0, 0, 0]
}
},
"jaw": {
"rotation": {
"0.0": [0, 0, 0],
"0.0417": [27.2, 0, 0],
"0.0833": [30, 0, 0],
"0.1667": [19, 0, 0],
"0.2083": [17.65, 0, 0],
"0.3333": [57.56, 0, 0],
"0.375": [60, 0, 0],
"0.4167": [56.99, 0, 0],
"0.7083": [4.23, 0, 0],
"0.7917": [0, 0, 0]
}
},
"fangs": {
"position": {
"0.0": [0, 0, 0],
"0.0417": [0, -0.5, 0],
"0.625": [0, -0.5, 0],
"0.6667": [0, 0, 0]
}
}
},
"sound_effects": {
"0.0": {
"effect": "pokemon.braixen.cry"
}
}
}
}
}
@@ -5,7 +5,7 @@
"description": {
"identifier": "geometry.caterpie",
"texture_width": 64,
"texture_height": 32,
"texture_height": 64,
"visible_bounds_width": 4,
"visible_bounds_height": 2.5,
"visible_bounds_offset": [0, 0.75, 0]
@@ -23,62 +23,62 @@
{
"name": "head",
"parent": "body",
"pivot": [0, 5, -6.25],
"pivot": [0, 5.25, -6.25],
"cubes": [
{"origin": [-4, 2, -12.25], "size": [8, 7, 6], "uv": [0, 0]},
{"origin": [-2, 2.25, -13.5], "size": [4, 3, 2], "pivot": [0, 3.75, -12.5], "rotation": [22.5, 0, 0], "uv": [28, 3]},
{"origin": [-4.5, 5.75, -12.5], "size": [9, 3, 0], "pivot": [0, 7.25, -12.5], "rotation": [10, 0, 0], "uv": [22, 0]}
{"origin": [-4, 2.25, -12.25], "size": [8, 7, 7], "uv": [0, 0]},
{"origin": [-2, 2.5, -13.5], "size": [4, 3, 2], "pivot": [0, 4, -12.5], "rotation": [22.5, 0, 0], "uv": [24, 30]},
{"origin": [-4.5, 6, -12.5], "size": [9, 4, 0], "pivot": [0, 7.5, -12.5], "rotation": [10, 0, 0], "uv": [30, 0]}
]
},
{
"name": "eyes",
"parent": "head",
"pivot": [0, 6.25, -10]
"pivot": [0, 6.5, -10]
},
{
"name": "eye_right",
"parent": "eyes",
"pivot": [-4.015, 6.25, -10],
"pivot": [-3.815, 5.95, -9.55],
"cubes": [
{"origin": [-4.02, 5.25, -11], "size": [0, 2, 2], "uv": [60, 0], "mirror": true},
{"origin": [-4.01, 4.75, -11.5], "size": [0, 3, 3], "uv": [0, -3], "mirror": true}
{"origin": [-3.82, 4.95, -10.55], "size": [0, 2, 2], "inflate": 0.2, "uv": [41, 37]},
{"origin": [-3.81, 4.45, -11.05], "size": [0, 3, 3], "inflate": 0.2, "uv": [33, 36]}
]
},
{
"name": "eyelid_right",
"parent": "eye_right",
"pivot": [-3.42, 6.25, -10],
"pivot": [-3.22, 5.95, -9.55],
"cubes": [
{"origin": [-3.92, 4.75, -11.5], "size": [1, 3, 3], "inflate": 0.01, "uv": [32, 16], "mirror": true}
{"origin": [-3.73, 4.45, -11.05], "size": [1, 3, 3], "inflate": 0.2, "uv": [0, 40]}
]
},
{
"name": "eye_left",
"parent": "eyes",
"pivot": [4.015, 6.25, -10],
"pivot": [3.815, 5.95, -9.55],
"cubes": [
{"origin": [4.02, 5.25, -11], "size": [0, 2, 2], "uv": [60, -2]},
{"origin": [4.01, 4.75, -11.5], "size": [0, 3, 3], "uv": [0, 0]}
{"origin": [3.82, 4.95, -10.55], "size": [0, 2, 2], "inflate": 0.2, "uv": [41, 31]},
{"origin": [3.81, 4.45, -11.05], "size": [0, 3, 3], "inflate": 0.2, "uv": [25, 36]}
]
},
{
"name": "eyelid_left",
"parent": "eye_left",
"pivot": [3.42, 6.25, -10],
"pivot": [3.22, 5.95, -9.55],
"cubes": [
{"origin": [2.92, 4.75, -11.5], "size": [1, 3, 3], "inflate": 0.01, "uv": [20, 13]}
{"origin": [2.73, 4.45, -11.05], "size": [1, 3, 3], "inflate": 0.2, "uv": [8, 40]}
]
},
{
"name": "body_segment",
"parent": "body",
"pivot": [0, 5, -6.25],
"pivot": [0, 5, -5.25],
"cubes": [
{"origin": [-3.5, 1, -7.25], "size": [7, 7, 6], "uv": [0, 13]},
{"origin": [-3.51, 3.5, -5.25], "size": [0, 3, 3], "uv": [32, 19], "mirror": true},
{"origin": [-3.52, 4, -4.75], "size": [0, 2, 2], "uv": [42, 0], "mirror": true},
{"origin": [3.51, 3.5, -5.25], "size": [0, 3, 3], "uv": [38, 19]},
{"origin": [3.52, 4, -4.75], "size": [0, 2, 2], "uv": [60, 2]}
{"origin": [-3.5, 1, -7.25], "size": [7, 7, 7], "uv": [0, 14]},
{"origin": [-3.51, 3.5, -4.25], "size": [0, 3, 3], "uv": [42, 4]},
{"origin": [-3.52, 4, -3.75], "size": [0, 2, 2], "uv": [36, 30]},
{"origin": [3.51, 3.5, -4.25], "size": [0, 3, 3], "uv": [20, 43]},
{"origin": [3.52, 4, -3.75], "size": [0, 2, 2], "uv": [46, 29]}
]
},
{
@@ -86,7 +86,7 @@
"parent": "body_segment",
"pivot": [-2.25, 1, -3.25],
"cubes": [
{"origin": [-3.25, 0, -4.25], "size": [2, 1, 2], "uv": [23, 26]}
{"origin": [-3.25, 0, -4.25], "size": [2, 1, 2], "uv": [44, 22]}
]
},
{
@@ -94,80 +94,88 @@
"parent": "body_segment",
"pivot": [2.25, 1, -3.25],
"cubes": [
{"origin": [1.25, 0, -4.25], "size": [2, 1, 2], "uv": [40, 13]}
{"origin": [1.25, 0, -4.25], "size": [2, 1, 2], "uv": [32, 43]}
]
},
{
"name": "body_segment2",
"parent": "body_segment",
"pivot": [0, 4, -1.25],
"pivot": [0, 4, -0.25],
"cubes": [
{"origin": [-3, 1.02, -2.25], "size": [6, 6, 6], "uv": [40, 0]},
{"origin": [-3.01, 3, -0.25], "size": [0, 3, 3], "uv": [32, 22], "mirror": true},
{"origin": [-3.02, 3.5, 0.25], "size": [0, 2, 2], "uv": [42, -2], "mirror": true},
{"origin": [3.01, 3, -0.25], "size": [0, 3, 3], "uv": [38, 22]},
{"origin": [3.02, 3.5, 0.25], "size": [0, 2, 2], "uv": [42, 2]}
{"origin": [-3, 1.02, -1.25], "size": [6, 6, 6], "uv": [0, 28]},
{"origin": [-3.01, 3, 0.75], "size": [0, 3, 3], "uv": [26, 43]},
{"origin": [-3.02, 3.5, 1.25], "size": [0, 2, 2], "uv": [46, 10]},
{"origin": [3.01, 3, 0.75], "size": [0, 3, 3], "uv": [40, 42]},
{"origin": [3.02, 3.5, 1.25], "size": [0, 2, 2], "uv": [4, 46]}
]
},
{
"name": "foot_right2",
"parent": "body_segment2",
"pivot": [-2, 1, 1.75],
"pivot": [-2, 1, 2.75],
"cubes": [
{"origin": [-3, 0, 0.75], "size": [2, 1, 2], "uv": [37, 16]}
{"origin": [-3, 0, 1.75], "size": [2, 1, 2], "uv": [38, 11]}
]
},
{
"name": "foot_left2",
"parent": "body_segment2",
"pivot": [2, 1, 1.75],
"pivot": [2, 1, 2.75],
"cubes": [
{"origin": [1, 0, 0.75], "size": [2, 1, 2], "uv": [40, 19]}
{"origin": [1, 0, 1.75], "size": [2, 1, 2], "uv": [30, 11]}
]
},
{
"name": "tail",
"parent": "body_segment2",
"pivot": [0, 5, 3.75],
"pivot": [0, 5, 4.75],
"cubes": [
{"origin": [-2.5, 1, 3.75], "size": [5, 4, 4], "uv": [46, 12]},
{"origin": [-2.51, 2.5, 4.75], "size": [0, 2, 2], "uv": [0, 11], "mirror": true},
{"origin": [-2.52, 3, 5.25], "size": [0, 1, 1], "uv": [40, 4], "mirror": true},
{"origin": [2.51, 2.5, 4.75], "size": [0, 2, 2], "uv": [44, 20]},
{"origin": [2.52, 3, 5.25], "size": [0, 1, 1], "uv": [40, 1]}
{"origin": [-2.5, 1, 4.75], "size": [5, 4, 4], "uv": [28, 14]},
{"origin": [-2.51, 2.5, 5.75], "size": [0, 2, 2], "uv": [12, 46]},
{"origin": [-2.52, 3, 6.25], "size": [0, 1, 1], "uv": [22, 40]},
{"origin": [2.51, 2.5, 5.75], "size": [0, 2, 2], "uv": [44, 25]},
{"origin": [2.52, 3, 6.25], "size": [0, 1, 1], "uv": [24, 28]}
]
},
{
"name": "tail2",
"parent": "tail",
"pivot": [0, 3, 7.75],
"pivot": [0, 3, 8.75],
"cubes": [
{"origin": [-2, 1, 7.75], "size": [4, 4, 4], "uv": [48, 20]},
{"origin": [-2.01, 2.25, 8.75], "size": [0, 2, 2], "uv": [0, 13], "mirror": true},
{"origin": [-2.02, 2.75, 9.25], "size": [0, 1, 1], "uv": [40, -1], "mirror": true},
{"origin": [2.01, 2.25, 8.75], "size": [0, 2, 2], "uv": [44, 22]},
{"origin": [2.02, 2.75, 9.25], "size": [0, 1, 1], "uv": [40, 2]}
{"origin": [-2, 1, 8.75], "size": [4, 4, 4], "uv": [28, 22]},
{"origin": [-2.01, 2.25, 9.75], "size": [0, 2, 2], "uv": [46, 14]},
{"origin": [-2.02, 2.75, 10.25], "size": [0, 1, 1], "uv": [32, 46]},
{"origin": [2.01, 2.25, 9.75], "size": [0, 2, 2], "uv": [0, 46]},
{"origin": [2.02, 2.75, 10.25], "size": [0, 1, 1], "uv": [26, 28]}
]
},
{
"name": "tail3",
"parent": "tail2",
"pivot": [0, 2.5, 11.75],
"pivot": [0, 2.5, 12.75],
"cubes": [
{"origin": [-1, 1, 11.75], "size": [2, 3, 4], "uv": [28, 8]},
{"origin": [-1.01, 1.5, 13], "size": [0, 2, 2], "uv": [0, 15], "mirror": true},
{"origin": [-1.02, 2, 13.5], "size": [0, 1, 1], "uv": [40, 0], "mirror": true},
{"origin": [1.01, 1.5, 13], "size": [0, 2, 2], "uv": [44, 24]},
{"origin": [1.02, 2, 13.5], "size": [0, 1, 1], "uv": [40, 3]}
{"origin": [-1, 1, 12.75], "size": [2, 3, 4], "uv": [30, 4]},
{"origin": [-1.01, 1.5, 14], "size": [0, 2, 2], "uv": [46, 18]},
{"origin": [-1.02, 2, 14.5], "size": [0, 1, 1], "uv": [46, 33]},
{"origin": [1.01, 1.5, 14], "size": [0, 2, 2], "uv": [8, 46]},
{"origin": [1.02, 2, 14.5], "size": [0, 1, 1], "uv": [20, 40]}
]
},
{
"name": "tail4",
"parent": "tail3",
"pivot": [0, 2.5, 14],
"pivot": [0, 2.5, 16.75],
"rotation": [-90, 0, 0],
"cubes": [
{"origin": [0, 3.75, 13], "size": [0, 7, 2], "uv": [27, 17]}
{"origin": [0, 2.5, 16.25], "size": [0, 1, 1], "uv": [17, 40]}
]
},
{
"name": "tail5",
"parent": "tail4",
"pivot": [0, 3.5, 16.75],
"cubes": [
{"origin": [-1, 3.5, 15.75], "size": [2, 5, 2], "uv": [3, 51]}
]
}
]
@@ -0,0 +1,583 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.delibird",
"texture_width": 128,
"texture_height": 64,
"visible_bounds_width": 3,
"visible_bounds_height": 3.5,
"visible_bounds_offset": [0, 1.25, 0]
},
"bones": [
{
"name": "delibird",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "delibird",
"pivot": [0, 7.1, 0]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 1.6, 0],
"cubes": [
{"origin": [-6.5, 1.6, -5], "size": [13, 10, 10], "uv": [0, 41]},
{"origin": [-1, 2.6, -5.01], "size": [2, 2, 0], "uv": [36, 46]}
]
},
{
"name": "chest",
"parent": "torso",
"pivot": [0, 11.6, 3.5],
"cubes": [
{"origin": [-5.5, 11.1, -4], "size": [11, 6, 8], "uv": [36, 25]}
]
},
{
"name": "beard",
"parent": "chest",
"pivot": [0, 17.1, -4],
"rotation": [-25, 0, 0],
"cubes": [
{"origin": [-3.5, 11.1, -4], "size": [7, 6, 3], "uv": [0, 13]}
]
},
{
"name": "beard1_left",
"parent": "beard",
"pivot": [3.5, 14.1, -4],
"cubes": [
{"origin": [3.5, 11.1, -4], "size": [2, 6, 0], "uv": [20, 6]}
]
},
{
"name": "beard1_right",
"parent": "beard",
"pivot": [-3.5, 14.1, -4],
"cubes": [
{"origin": [-5.5, 11.1, -4], "size": [2, 6, 0], "uv": [24, 6], "mirror": true}
]
},
{
"name": "beard2",
"parent": "beard",
"pivot": [0, 11.1, -4],
"rotation": [30, 0, 0],
"cubes": [
{"origin": [-2.5, 7.1, -4], "size": [5, 4, 3], "uv": [20, 16]}
]
},
{
"name": "beard2_left",
"parent": "beard2",
"pivot": [2.5, 9.1, -4],
"cubes": [
{"origin": [2.5, 7.1, -4], "size": [2, 4, 0], "uv": [20, 12]}
]
},
{
"name": "beard2_right",
"parent": "beard2",
"pivot": [-2.5, 9.1, -4],
"cubes": [
{"origin": [-4.5, 7.1, -4], "size": [2, 4, 0], "uv": [24, 12], "mirror": true}
]
},
{
"name": "beard3",
"parent": "beard2",
"pivot": [0, 7.1, -4],
"rotation": [7.5, 0, 0],
"cubes": [
{"origin": [-2.5, 4.1, -4], "size": [5, 3, 0], "uv": [34, 25]}
]
},
{
"name": "arms",
"parent": "chest",
"pivot": [0, 11.6, 3.5]
},
{
"name": "arm_left",
"parent": "arms",
"pivot": [5, 15.1, 0],
"cubes": [
{"origin": [4, 13.1, -2.5], "size": [6, 3, 5], "inflate": 0.01, "uv": [106, 39]}
]
},
{
"name": "arm_left2",
"parent": "arm_left",
"pivot": [10, 16.1, 2],
"cubes": [
{"origin": [10, 13.1, -2], "size": [3, 3, 4], "uv": [46, 54]}
]
},
{
"name": "arm_left3",
"parent": "arm_left2",
"pivot": [13, 15.6, 1.5],
"cubes": [
{"origin": [13, 13.6, -1.5], "size": [2, 2, 3], "uv": [0, 8]}
]
},
{
"name": "arm_right",
"parent": "arms",
"pivot": [-5, 15.1, 0],
"cubes": [
{"origin": [-10, 13.1, -2.5], "size": [6, 3, 5], "inflate": 0.01, "uv": [106, 47], "mirror": true}
]
},
{
"name": "arm_right2",
"parent": "arm_right",
"pivot": [-10, 16.1, 2],
"cubes": [
{"origin": [-13, 13.1, -2], "size": [3, 3, 4], "uv": [36, 39], "mirror": true}
]
},
{
"name": "arm_right3",
"parent": "arm_right2",
"pivot": [-13, 15.6, 1.5],
"cubes": [
{"origin": [-15, 13.6, -1.5], "size": [2, 2, 3], "uv": [10, 8], "mirror": true}
]
},
{
"name": "neck",
"parent": "chest",
"pivot": [0.5, 17.1, 0],
"cubes": [
{"origin": [-3.5, 16.6, -2.5], "size": [7, 2, 5], "uv": [104, 55]}
]
},
{
"name": "head",
"parent": "neck",
"pivot": [0.25, 17.6, 0],
"cubes": [
{"origin": [-4.5, 17.1, -4.5], "size": [9, 9, 9], "uv": [0, 23]},
{"origin": [-5, 17.1, -4.5], "size": [10, 4, 9], "inflate": 0.01, "uv": [56, 6]}
]
},
{
"name": "eyes",
"parent": "head",
"pivot": [0.25, 22.1, -4.5]
},
{
"name": "eye_outline_left",
"parent": "eyes",
"pivot": [2.5, 21.1, -4.52],
"cubes": [
{"origin": [0.5, 19.1, -4.52], "size": [4, 4, 0], "uv": [8, 0]}
]
},
{
"name": "eye_left",
"parent": "eye_outline_left",
"pivot": [2.2, 21.1, -4.53],
"cubes": [
{"origin": [0.8, 19.6, -4.63], "size": [3, 3, 1], "inflate": -0.1, "uv": [8, 4]}
]
},
{
"name": "pupil_left",
"parent": "eye_left",
"pivot": [1.5, 21.1, -4.54],
"cubes": [
{"origin": [0.6, 20.1, -4.69], "size": [2, 2, 1], "inflate": -0.15, "uv": [16, 3]}
]
},
{
"name": "pupil_left2",
"parent": "pupil_left",
"pivot": [1.2, 21.1, -4.55],
"cubes": [
{"origin": [0.9, 20.6, -4.6], "size": [1, 1, 1], "inflate": -0.05, "uv": [22, 2]}
]
},
{
"name": "eyelid_left",
"parent": "eye_left",
"pivot": [2.2, 21.1, -3.94],
"cubes": [
{"origin": [0.7, 19.6, -4.45], "size": [3, 3, 1], "inflate": 0.01, "uv": [28, 9]}
]
},
{
"name": "eye_outline_right",
"parent": "eyes",
"pivot": [-2.5, 21.1, -4.52],
"cubes": [
{"origin": [-4.5, 19.1, -4.52], "size": [4, 4, 0], "uv": [0, 0], "mirror": true}
]
},
{
"name": "eye_right",
"parent": "eye_outline_right",
"pivot": [-2.2, 21.1, -4.53],
"cubes": [
{"origin": [-3.8, 19.6, -4.63], "size": [3, 3, 1], "inflate": -0.1, "uv": [0, 4], "mirror": true}
]
},
{
"name": "pupil_right",
"parent": "eye_right",
"pivot": [-1.5, 21.1, -4.54],
"cubes": [
{"origin": [-2.6, 20.1, -4.69], "size": [2, 2, 1], "inflate": -0.15, "uv": [16, 0], "mirror": true}
]
},
{
"name": "pupil_right2",
"parent": "pupil_right",
"pivot": [-1.2, 21.1, -4.55],
"cubes": [
{"origin": [-1.9, 20.6, -4.6], "size": [1, 1, 1], "inflate": -0.05, "uv": [22, 0], "mirror": true}
]
},
{
"name": "eyelid_right",
"parent": "eye_right",
"pivot": [-2.2, 21.1, -3.94],
"cubes": [
{"origin": [-3.7, 19.6, -4.45], "size": [3, 3, 1], "inflate": 0.01, "uv": [28, 5], "mirror": true}
]
},
{
"name": "beak",
"parent": "head",
"pivot": [0, 20.65, -4.5],
"rotation": [6, 0, 0],
"cubes": [
{"origin": [-1.5, 18.75, -7], "size": [3, 2, 3], "inflate": -0.09, "uv": [52, 2]},
{"origin": [-1, 18.75, -8.8], "size": [2, 2, 2], "inflate": -0.09, "uv": [47, 1]}
]
},
{
"name": "jaw",
"parent": "beak",
"pivot": [0, 19.25, -4.5],
"cubes": [
{"origin": [-1.5, 18.25, -7], "size": [3, 1, 3], "inflate": -0.1, "uv": [48, 7]},
{"origin": [-1, 18.25, -8.8], "size": [2, 1, 2], "inflate": -0.1, "uv": [57, 7]}
]
},
{
"name": "head_fur",
"parent": "head",
"pivot": [4, 21.1, 4.5]
},
{
"name": "head_fur_left",
"parent": "head_fur",
"pivot": [5, 21.1, -1.5],
"rotation": [0, 20, 0],
"cubes": [
{"origin": [5, 17.1, -1.5], "size": [0, 4, 3], "uv": [48, 8]}
]
},
{
"name": "head_fur_left2",
"parent": "head_fur",
"pivot": [5, 21.1, 1.5],
"rotation": [0, 20, 0],
"cubes": [
{"origin": [5, 17.1, 1.5], "size": [0, 4, 3], "uv": [61, -3]}
]
},
{
"name": "head_fur_right",
"parent": "head_fur",
"pivot": [-5, 21.1, -1.5],
"rotation": [0, -20, 0],
"cubes": [
{"origin": [-5, 17.1, -1.5], "size": [0, 4, 3], "uv": [54, 8], "mirror": true}
]
},
{
"name": "head_fur_right2",
"parent": "head_fur",
"pivot": [-5, 21.1, 1.5],
"rotation": [0, -20, 0],
"cubes": [
{"origin": [-5, 17.1, 1.5], "size": [0, 4, 3], "uv": [67, -3], "mirror": true}
]
},
{
"name": "head_fur_left_top",
"parent": "head_fur",
"pivot": [4.5, 21.6, -1.5],
"rotation": [0, 20, 0],
"cubes": [
{"origin": [4.5, 21.6, -1.5], "size": [0, 3, 3], "uv": [73, -3]}
]
},
{
"name": "head_fur_right_top",
"parent": "head_fur",
"pivot": [-4.5, 21.6, -1.5],
"rotation": [0, -20, 0],
"cubes": [
{"origin": [-4.5, 21.6, -1.5], "size": [0, 3, 3], "uv": [73, 0], "mirror": true}
]
},
{
"name": "head_fur_back",
"parent": "head_fur",
"pivot": [0, 23.1, 4.5],
"rotation": [-70, 0, 0],
"cubes": [
{"origin": [-5, 23.1, 4.5], "size": [10, 0, 3], "uv": [33, 16]}
]
},
{
"name": "head_fur_back2",
"parent": "head_fur",
"pivot": [0, 20.1, 4.5],
"rotation": [-70, 0, 0],
"cubes": [
{"origin": [-5.5, 20.1, 4.5], "size": [11, 0, 3], "uv": [33, 19]}
]
},
{
"name": "head_fur_back3",
"parent": "head_fur",
"pivot": [0, 17.1, 4.1],
"rotation": [-70, 0, 0],
"cubes": [
{"origin": [-5.5, 17.1, 4.1], "size": [11, 0, 3], "uv": [33, 22]}
]
},
{
"name": "head_fur_front_left",
"parent": "head",
"pivot": [0, 24.1, -4.5],
"rotation": [1, 0, 0]
},
{
"name": "head_fur_front_left_rotation",
"parent": "head_fur_front_left",
"pivot": [0, 24.1, -4.5],
"rotation": [0, 0, 45],
"cubes": [
{"origin": [0, 24.1, -4.5], "size": [4, 5, 0], "uv": [27, 0]}
]
},
{
"name": "head_fur_front_left2",
"parent": "head_fur_front_left_rotation",
"pivot": [0, 29.1, -4.5],
"rotation": [-45, 0, 0],
"cubes": [
{"origin": [-3, 29.1, -4.5], "size": [7, 5, 0], "uv": [58, 19]}
]
},
{
"name": "head_fur_front_left3",
"parent": "head_fur_front_left2",
"pivot": [4, 34.1, -4.5],
"rotation": [-20, 0, 0],
"cubes": [
{"origin": [-2, 34.1, -4.5], "size": [6, 3, 0], "uv": [36, 10]}
]
},
{
"name": "head_fur_front_right",
"parent": "head",
"pivot": [0, 24.1, -4.5],
"rotation": [1, 0, 0]
},
{
"name": "head_fur_front_right_rotation",
"parent": "head_fur_front_right",
"pivot": [0, 24.1, -4.5],
"rotation": [0, 0, -45],
"cubes": [
{"origin": [-4, 24.1, -4.5], "size": [4, 5, 0], "uv": [35, 0], "mirror": true}
]
},
{
"name": "head_fur_front_right2",
"parent": "head_fur_front_right_rotation",
"pivot": [0, 29.1, -4.5],
"rotation": [-45, 0, 0],
"cubes": [
{"origin": [-4, 29.1, -4.5], "size": [7, 5, 0], "uv": [36, 5], "mirror": true}
]
},
{
"name": "head_fur_front_right3",
"parent": "head_fur_front_right2",
"pivot": [-4, 34.1, -4.5],
"rotation": [-20, 0, 0],
"cubes": [
{"origin": [-4, 34.1, -4.5], "size": [6, 3, 0], "uv": [36, 13], "mirror": true}
]
},
{
"name": "tail",
"parent": "torso",
"pivot": [0, 4.6, 4.5],
"rotation": [-15, 0, 0],
"cubes": [
{"origin": [-1.5, 3.1, 3.5], "size": [3, 3, 3], "uv": [100, 33]}
]
},
{
"name": "tail2",
"parent": "tail",
"pivot": [0, 4.6, 5.5],
"cubes": [
{"origin": [-2.5, 2.1, 5.5], "size": [5, 5, 3], "uv": [73, 19]}
]
},
{
"name": "tail3",
"parent": "tail2",
"pivot": [0, 4.1, 7.5],
"rotation": [12.5, 0, 0],
"cubes": [
{"origin": [-3.5, 1.1, 7.5], "size": [9, 8, 7], "inflate": 0.01, "uv": [85, 0]}
]
},
{
"name": "tail4",
"parent": "tail3",
"pivot": [5.5, 4.6, 14],
"cubes": [
{"origin": [5.5, 1.6, 8], "size": [5, 7, 6], "uv": [89, 15]}
]
},
{
"name": "tail5",
"parent": "tail4",
"pivot": [10.5, 5.1, 13],
"rotation": [0, -90, 0],
"cubes": [
{"origin": [6.5, 2.6, 10], "size": [4, 5, 4], "uv": [111, 15]}
]
},
{
"name": "tail6",
"parent": "tail5",
"pivot": [8.5, 5.1, 10],
"cubes": [
{"origin": [7, 3.6, 6], "size": [3, 3, 5], "uv": [83, 28]}
]
},
{
"name": "tail7",
"parent": "tail6",
"pivot": [8.5, 5.1, 6],
"cubes": [
{"origin": [7.5, 4.1, 0], "size": [2, 2, 7], "uv": [80, 36]}
]
},
{
"name": "tail_end",
"parent": "tail7",
"pivot": [8.5, 5.1, 1],
"cubes": [
{"origin": [7, 3.6, -2], "size": [3, 3, 3], "uv": [91, 37]}
]
},
{
"name": "tail_end_left",
"parent": "tail_end",
"pivot": [10, 5.1, -2],
"rotation": [0, -15, 0],
"cubes": [
{"origin": [10, 2.6, -7], "size": [0, 5, 5], "uv": [114, 19]}
]
},
{
"name": "tail_end_right",
"parent": "tail_end",
"pivot": [7, 5.1, -2],
"rotation": [0, 12.5, 0],
"cubes": [
{"origin": [7, 2.6, -7], "size": [0, 5, 5], "uv": [114, 24]}
]
},
{
"name": "tail_end_top",
"parent": "tail_end",
"pivot": [8.5, 6.6, -2],
"cubes": [
{"origin": [6, 6.6, -7], "size": [5, 0, 5], "pivot": [8.5, 6.6, -2], "rotation": [-15, 0, 0], "uv": [89, 28]}
]
},
{
"name": "tail_end_bottom",
"parent": "tail_end",
"pivot": [8.5, 3.6, -2],
"rotation": [15, 0, 0],
"cubes": [
{"origin": [6, 3.6, -7], "size": [5, 0, 5], "uv": [99, 28]}
]
},
{
"name": "legs",
"parent": "body",
"pivot": [0, 5.1, 0]
},
{
"name": "leg_left",
"parent": "legs",
"pivot": [4.5, 7.1, 0],
"cubes": [
{"origin": [1.5, 1.1, -4], "size": [6, 7, 8], "uv": [66, 46]}
]
},
{
"name": "foot_left",
"parent": "leg_left",
"pivot": [4.5, 1.1, 0],
"cubes": [
{"origin": [3, 0.1, -3.5], "size": [3, 1, 6], "inflate": 0.01, "uv": [86, 45]}
]
},
{
"name": "toe_left",
"parent": "foot_left",
"pivot": [6, 0.1, -3],
"cubes": [
{"origin": [3, 0.1, -5], "size": [3, 0, 2], "uv": [65, 25]}
]
},
{
"name": "leg_right",
"parent": "legs",
"pivot": [-4.5, 7.1, 0],
"cubes": [
{"origin": [-7.5, 1.1, -4], "size": [6, 7, 8], "uv": [46, 39], "mirror": true}
]
},
{
"name": "foot_right",
"parent": "leg_right",
"pivot": [-4.5, 1.1, 0],
"cubes": [
{"origin": [-6, 0.1, -3.5], "size": [3, 1, 6], "inflate": 0.01, "uv": [88, 56], "mirror": true}
]
},
{
"name": "toe_right",
"parent": "foot_right",
"pivot": [-6, 0.1, -3],
"cubes": [
{"origin": [-6, 0.1, -5], "size": [3, 0, 2], "uv": [65, 27], "mirror": true}
]
}
]
}
]
}
@@ -324,7 +324,7 @@
"name": "head_correction",
"parent": "head",
"pivot": [0, 6.2, -15],
"rotation": [-90, 0, 0]
"rotation": [0, 0, 0]
},
{
"name": "head_ai",
@@ -335,6 +335,7 @@
"name": "head_angle",
"parent": "head_ai",
"pivot": [0, 6.5, -16],
"rotation": [-90, 0, 0],
"cubes": [
{"origin": [-3.5, 2.49, -22], "size": [7, 7, 7], "uv": [0, 0]}
]
@@ -32,16 +32,16 @@
},
"sleep": {
"poseTypes": ["SLEEP"],
"animations": ["q.bedrock('raichu_alolan', 'ground_sleep')"]
"isTouchingWater": false,
"animations": ["q.bedrock('raichu_alolan', 'sleep')"]
},
"surface_sleep": {
"poseTypes": ["SLEEP"],
"isTouchingWater": true,
"animations": [
"q.look('head')",
"q.bedrock('raichu_alolan', 'ground_sleep')"
"q.bedrock('raichu_alolan', 'sleep')"
],
"quirks": ["q.bedrock_quirk('raichu_alolan', 'blink')"],
"transformedParts": [
{
"part": "body",
@@ -0,0 +1,53 @@
{
"portraitScale": 1.61,
"portraitTranslation": [0, 0.74, 0],
"profileScale": 0.52,
"profileTranslation": [0, 1, 0],
"rootBone": "delibird",
"poses": {
"standing": {
"poseTypes": [
"STAND",
"NONE",
"FLOAT",
"PORTRAIT",
"PROFILE"
],
"animations": [
"q.look('head')",
"q.bedrock('delibird', 'ground_idle')"
],
"quirks": [
"q.bedrock_quirk('delibird', 'blink')"
]
},
"walking": {
"poseTypes": [
"WALK",
"SWIM"
],
"animations": [
"q.look('head')",
"q.bedrock('delibird', 'ground_idle')",
"q.biped_walk(0.85, 0.75, 'leg_left', 'leg_right')"
],
"quirks": [
"q.bedrock_quirk('delibird', 'blink')"
]
},
"flying": {
"poseTypes": [
"FLY",
"HOVER"
],
"animations": [
"q.sine_wing_flap(0.7, 0.4, 25, 'z', 'arm_right3', 'arm_right')",
"q.look('head')",
"q.bedrock('delibird', 'ground_idle')"
],
"quirks": [
"q.bedrock_quirk('delibird', 'blink')"
]
}
}
}
@@ -11,12 +11,12 @@
"standing": {
"poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"],
"isBattle": false,
"animations": ["q.look('head')", "q.bedrock('snivy', 'ground_idle')"],
"animations": ["q.look('head_ai')", "q.bedrock('snivy', 'ground_idle')"],
"quirks": ["q.bedrock_quirk('snivy', 'blink')"]
},
"walking": {
"poseTypes": ["WALK"],
"animations": ["q.look('head')", "q.bedrock('snivy', 'ground_walk')"],
"animations": ["q.look('head_ai')", "q.bedrock('snivy', 'ground_walk')"],
"quirks": ["q.bedrock_quirk('snivy', 'blink')"]
},
"sleep": {
@@ -11,12 +11,12 @@
"standing": {
"poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"],
"isBattle": false,
"animations": ["q.look('head')", "q.bedrock('servine', 'ground_idle')"],
"animations": ["q.look('head_ai')", "q.bedrock('servine', 'ground_idle')"],
"quirks": ["q.bedrock_quirk('servine', 'blink')"]
},
"walking": {
"poseTypes": ["WALK"],
"animations": ["q.look('head')", "q.bedrock('servine', 'ground_idle')"],
"animations": ["q.look('head_ai')", "q.bedrock('servine', 'ground_idle')"],
"quirks": ["q.bedrock_quirk('servine', 'blink')"]
},
"sleep": {
@@ -8,15 +8,41 @@
"cry": "q.bedrock_stateful('serperior', 'cry')"
},
"poses": {
"water_surface": {
"poseTypes": [
"STAND"
],
"isTouchingWater": true,
"animations": [
"q.look('head')",
"q.bedrock('serperior', 'ground_walk')"
],
"quirks": ["q.bedrock_quirk('serperior', 'blink')"]
},
"standing": {
"poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"],
"poseTypes": [
"STAND",
"NONE",
"PORTRAIT",
"PROFILE"
],
"isBattle": false,
"animations": ["q.look('head')", "q.bedrock('serperior', 'ground_idle')"],
"animations": [
"q.look('head')",
"q.bedrock('serperior', 'ground_idle')"
],
"quirks": ["q.bedrock_quirk('serperior', 'blink')"]
},
"walking": {
"poseTypes": ["WALK"],
"animations": ["q.look('head')", "q.bedrock('serperior', 'ground_walk')"],
"poseTypes": [
"WALK",
"FLOAT",
"SWIM"
],
"animations": [
"q.look('head')",
"q.bedrock('serperior', 'ground_walk')"
],
"quirks": ["q.bedrock_quirk('serperior', 'blink')"]
},
"sleep": {
@@ -27,7 +27,7 @@
"poseTypes": ["WALK", "SWIM"],
"animations": [
"q.look('head')",
"q.bedrock('braixen', 'ground_walk_old')"
"q.bedrock('braixen', 'ground_walk')"
],
"quirks": ["q.bedrock_quirk('braixen', 'blink')"],
"transformedParts": [
@@ -27,7 +27,7 @@
"poseTypes": ["WALK", "SWIM"],
"animations": [
"q.look('head')",
"q.bedrock('delphox', 'ground_walk_old')"
"q.bedrock('delphox', 'ground_walk')"
],
"quirks": ["q.bedrock_quirk('delphox', 'blink')"],
"transformedParts": [
@@ -9,8 +9,17 @@
"texture": "cobblemon:textures/pokemon/0004_charmander/charmander.png",
"layers": [
{
"name": "glow",
"texture": "cobblemon:textures/pokemon/0004_charmander/charmander_emissive.png",
"name": "flame",
"texture": {
"frames": [
"cobblemon:textures/pokemon/0004_charmander/charmander_flame1.png",
"cobblemon:textures/pokemon/0004_charmander/charmander_flame2.png",
"cobblemon:textures/pokemon/0004_charmander/charmander_flame3.png",
"cobblemon:textures/pokemon/0004_charmander/charmander_flame4.png"
],
"fps": 10,
"loop": true
},
"emissive": true,
"translucent": true
}
@@ -21,8 +30,17 @@
"texture": "cobblemon:textures/pokemon/0004_charmander/charmander_shiny.png",
"layers": [
{
"name": "glow",
"texture": "cobblemon:textures/pokemon/0004_charmander/charmander_shiny_emissive.png",
"name": "flame",
"texture": {
"frames": [
"cobblemon:textures/pokemon/0004_charmander/charmander_shiny_flame1.png",
"cobblemon:textures/pokemon/0004_charmander/charmander_shiny_flame2.png",
"cobblemon:textures/pokemon/0004_charmander/charmander_shiny_flame3.png",
"cobblemon:textures/pokemon/0004_charmander/charmander_shiny_flame4.png"
],
"fps": 10,
"loop": true
},
"emissive": true,
"translucent": true
}
@@ -9,8 +9,17 @@
"texture": "cobblemon:textures/pokemon/0005_charmeleon/charmeleon.png",
"layers": [
{
"name": "glow",
"texture": "cobblemon:textures/pokemon/0005_charmeleon/charmeleon_emissive.png",
"name": "flame",
"texture": {
"frames": [
"cobblemon:textures/pokemon/0005_charmeleon/charmeleon_flame1.png",
"cobblemon:textures/pokemon/0005_charmeleon/charmeleon_flame2.png",
"cobblemon:textures/pokemon/0005_charmeleon/charmeleon_flame3.png",
"cobblemon:textures/pokemon/0005_charmeleon/charmeleon_flame4.png"
],
"fps": 10,
"loop": true
},
"emissive": true,
"translucent": true
}
@@ -21,8 +30,17 @@
"texture": "cobblemon:textures/pokemon/0005_charmeleon/charmeleon_shiny.png",
"layers": [
{
"name": "glow",
"texture": "cobblemon:textures/pokemon/0005_charmeleon/charmeleon_shiny_emissive.png",
"name": "flame",
"texture": {
"frames": [
"cobblemon:textures/pokemon/0005_charmeleon/charmeleon_shiny_flame1.png",
"cobblemon:textures/pokemon/0005_charmeleon/charmeleon_shiny_flame2.png",
"cobblemon:textures/pokemon/0005_charmeleon/charmeleon_shiny_flame3.png",
"cobblemon:textures/pokemon/0005_charmeleon/charmeleon_shiny_flame4.png"
],
"fps": 10,
"loop": true
},
"emissive": true,
"translucent": true
}
@@ -0,0 +1,17 @@
{
"species": "cobblemon:delibird",
"order": 0,
"variations": [
{
"aspects": [],
"poser": "cobblemon:delibird",
"model": "cobblemon:delibird.geo",
"texture": "cobblemon:textures/pokemon/0225_delibird/delibird.png",
"layers": []
},
{
"aspects": ["shiny"],
"texture": "cobblemon:textures/pokemon/0225_delibird/delibird_shiny.png"
}
]
}
@@ -14,14 +14,14 @@
"model": "cobblemon:whiscash_nero.geo",
"texture": "cobblemon:textures/pokemon/0340_whiscash/whiscash_nero.png"
},
{
"aspects": ["shiny"],
"texture": "cobblemon:textures/pokemon/0340_whiscash/whiscash_shiny.png"
},
{
"aspects": ["whiscash_nero", "shiny"],
"model": "cobblemon:whiscash_nero.geo",
"texture": "cobblemon:textures/pokemon/0340_whiscash/whiscash_nero_shiny.png"
},
{
"aspects": ["shiny"],
"texture": "cobblemon:textures/pokemon/0340_whiscash/whiscash_shiny.png"
}
]
}
@@ -490,14 +490,14 @@
"block.cobblemon.large_budding_black_tumblestone": "Große Schwarzglanzsteinknospe",
"block.cobblemon.black_tumblestone_cluster": "Schwarzglanzsteinhaufen",
"block.cobblemon.black_tumblestone_block": "Schwarzglanzsteinblock",
"cobblemon.overflow_no_pc": "Deine Party war voll und du hast keinen PC!",
"cobblemon.overflow_no_space": "Deine und %1$s Party war voll!",
"cobblemon.overflow_to_pc": "Deine Party war voll! %1$s wurde zu %2$s hinzugefügt.",
"cobblemon.overflow_no_pc": "Dein Team war voll und du hast keinen PC!",
"cobblemon.overflow_no_space": "Deine und %1$s Team war voll!",
"cobblemon.overflow_to_pc": "Dein Team war voll! %1$s wurde zu %2$s hinzugefügt.",
"cobblemon.your_pc": "Dein PC",
"cobblemon.command.pokespawn.invalid-pokemon": "Ungültiger Pokémon Name",
"cobblemon.command.pokespawn.invalid-move": "Ungültige Attacke",
"cobblemon.command.clearparty.nonethere": "Es sind keine Pokémon in %1$s's Party.",
"cobblemon.command.clearparty.cleared": "%1$s's Party wurde gelöscht.",
"cobblemon.command.clearparty.nonethere": "Es sind keine Pokémon in %1$s's Team.",
"cobblemon.command.clearparty.cleared": "%1$s's Team wurde gelöscht.",
"cobblemon.command.clearpc.cleared": "%1$s's PC wurde gelöscht.",
"cobblemon.command.dialogue.invalid-dialogue": "Invalid dialogue identifier",
"cobblemon.ui.generic.yes": "Ja",
@@ -563,8 +563,8 @@
"cobblemon.ui.interact.trade": "Tauschen",
"cobblemon.ui.interact.battle": "Kämpfen",
"cobblemon.ui.interact.mount.shoulder": "Schulter",
"key.cobblemon.upshiftparty": "Party Auswahl nach oben",
"key.cobblemon.downshiftparty": "Party Auswahl nach unten",
"key.cobblemon.upshiftparty": "Team Auswahl nach oben",
"key.cobblemon.downshiftparty": "Team Auswahl nach unten",
"key.cobblemon.hideparty": "Team-UI Verstecken",
"key.cobblemon.throwpartypokemon": "Pokémon rauswerfen",
"key.cobblemon.pokenavigator": "PokéNav öffnen",
@@ -591,11 +591,11 @@
"cobblemon.subtitle.fossilmachine.unprotected": "Fossil-Restaurator-Schutz deaktiviert",
"cobblemon.subtitle.fossilmachine.assemble": "Fossil-Restaurator erstellt",
"cobblemon.healingmachine.alreadyinuse": "Dieser Heiler wird bereits benutzt!",
"cobblemon.healingmachine.nopokemon": "Kein Pokémon in deiner Party benötigt heilung!",
"cobblemon.healingmachine.nopokemon": "Kein Pokémon in deinem Team benötigt heilung!",
"cobblemon.healingmachine.alreadyhealed": "Deine Pokémon werden schon geheilt!",
"cobblemon.healingmachine.healing": "Deine Pokémon werden geheilt!",
"cobblemon.healingmachine.healed": "Deine Pokemon wurden geheilt!",
"cobblemon.healingmachine.notenoughcharge": "Diese Maschine braucht %s mehr Ladungen zum heilen deiner Party!",
"cobblemon.healingmachine.notenoughcharge": "Diese Maschine braucht %s mehr Ladungen zum heilen deines Teams!",
"cobblemon.healingmachine.inbattle": "Du kannst keine Heilmaschine im Kampf benutzen!",
"cobblemon.healingmachine.alreadyhealing": "Dein Pokémonteam ist bereits in einem anderen Heiler!",
"cobblemon.pc.inbattle": "Du kannst keinen PC im Kampf benutzen!",
@@ -779,7 +779,7 @@
"cobblemon.command.pokemonedit": "%2$s' %1$s editiert.",
"cobblemon.command.teach": "%2$s's %1$s hat %3$s gelernt.",
"cobblemon.command.teach.already_knows": "%1$s kennt %2$s bereits!",
"cobblemon.command.healpokemon.heal": "%1$s's Party wurde komplett geheilt.",
"cobblemon.command.healpokemon.heal": "%1$s's Team wurde komplett geheilt.",
"cobblemon.command.friendship": "%1$s hat %2$s Freundschaftpunkte.",
"cobblemon.command.givepokemon.nospecies": "Fehler: Du musst einen Pokémonnamen oder 'random' angeben",
"cobblemon.command.spawnpokemon.nospecies": "Fehler: Du musst entweder ein Pokémon oder 'random' angeben",
@@ -791,7 +791,7 @@
"cobblemon.command.pokebox.box_is_full": "Box %1$s dieses Spielers ist voll.",
"cobblemon.command.pokebox.storage_is_full": "Der Speicher dieses Spielers ist voll.",
"cobblemon.command.pokebox.last_pokemon": "Der letzte Pokémon dieses Spielers wurde nicht an den PC geschickt.",
"cobblemon.command.pokemonrestart": "%1$s's Party und PC wurden gelöscht.",
"cobblemon.command.pokemonrestart": "%1$s's Team und PC wurden gelöscht.",
"advancements.cobblemon.root": "Die Welt von Cobblemon!",
"advancements.cobblemon.root.description": "Wähle ein Starterpokémon und beginne ein neues Abenteuer",
"advancements.cobblemon.obtain_leftovers": "Reduzieren, Wiederverwenden, Recyceln!",
@@ -875,7 +875,7 @@
"advancements.cobblemon.use_candy": "Süßer Zahn",
"advancements.cobblemon.use_candy.description": "Verwende ein beliebiges EP-Bonbon auf einem Pokémon",
"advancements.cobblemon.own_zangoose_seviper": "Freunde widerwillen",
"advancements.cobblemon.own_zangoose_seviper.description": "Habe gleichzeitig einen Zangoose und Seviper in deiner Party",
"advancements.cobblemon.own_zangoose_seviper.description": "Habe gleichzeitig einen Zangoose und Seviper in deinem Team",
"advancements.cobblemon.obtain_fossil": "Befrage das Fossil",
"advancements.cobblemon.obtain_fossil.description": "Discover a fossil buried in ancient ruins",
"advancements.cobblemon.evolve_gholdengo_netherite": "Bedeck dich mit Schrott",
@@ -1822,7 +1822,7 @@
"cobblemon.ability.neuroforce": "Zerebralmacht",
"cobblemon.ability.neuroforce.desc": "Erhöht die Stärke von sehr effektiven Attacken.",
"cobblemon.ability.neutralizinggas": "Reaktionsgas",
"cobblemon.ability.neutralizinggas.desc": "Solange ein Pokémon mit der Fähigkeit Reaktionsgas am Kampf beteiligt ist, werden die Fähigkeiten aller anderen Pokémon unterdrückt oder aufgehoben.",
"cobblemon.ability.neutralizinggas.desc": "Solange das Pokémon am Kampf beteiligt ist, werden die Fähigkeiten aller anderen Pokémon unterdrückt oder aufgehoben.",
"cobblemon.ability.noguard": "Schildlos",
"cobblemon.ability.noguard.desc": "Alle Attacken des oder auf das Pokémon gelingen aufgrund seiner deckungslosen Kampftaktik.",
"cobblemon.ability.normalize": "Regulierung",
@@ -6225,5 +6225,13 @@
"cobblemon.ui.pokedex.info.form.bluestriped": "Blau gestreift",
"cobblemon.ui.pokedex.info.form.vivillon-wings-archipelago": "Archipel",
"cobblemon.ui.pokedex.info.form.vivillon-wings-continental": "Kontinental",
"cobblemon.ui.pokedex.info.form.whitestriped": "Weiß gestreift"
"cobblemon.ui.pokedex.info.form.whitestriped": "Weiß gestreift",
"cobblemon.ui.pokedex.info.form.shulker": "Shulker",
"cobblemon.ui.pokedex.info.form.zen_mode": "Trance-Modus",
"cobblemon.subtitle.pokemon.shiny_ambient": "Wildes Schillerndes Pokémon glitzert!",
"cobblemon.battle.error.no_party": "%1$s hat kein Pokémon Team verfügbar.",
"cobblemon.ability.embodyaspectcornerstone": "Erinnerungskraft - Fundamentmaske",
"cobblemon.ability.embodyaspecthearthflame": "Erinnerungskraft - Ofenmaske",
"cobblemon.ability.embodyaspectteal": "Erinnerungskraft - Türkisgrüne Maske",
"cobblemon.ability.embodyaspectwellspring": "Erinnerungskraft - Brunnenmaske"
}
@@ -1268,7 +1268,6 @@
"cobblemon.ui.status.psn": "PSN",
"cobblemon.ui.status.slp": "SLP",
"cobblemon.ui.status.tox": "PSN",
"cobblemon.battle.ui.fight": "Fight",
"cobblemon.battle.ui.switch": "Switch",
"cobblemon.battle.ui.capture": "Catch",
@@ -1278,11 +1277,6 @@
"cobblemon.battle.ui.hide_label": "Press %1$s to move around.",
"cobblemon.battle.ui.actions_label": "You need to choose an action. Press %1$s.",
"cobblemon.battle.ui.effectiveness.normal": "%1$sx Normal",
"cobblemon.battle.ui.effectiveness.super_effective": "%1$sx Super Effective",
"cobblemon.battle.ui.effectiveness.resistance": "%1$sx Resistance",
"cobblemon.battle.ui.effectiveness.immunity": "%1$sx Immunity",
"cobblemon.ui.evolve": "Evolve",
"cobblemon.ui.evolution": "Evolution",
"cobblemon.ui.evolve.hint": "%1$s seems ready to evolve!",
@@ -2011,6 +2005,7 @@
"cobblemon.battle.end.illusion": "%1$s's illusion wore off!",
"cobblemon.battle.end.neutralizinggas": "The effects of the neutralizing gas wore off!",
"cobblemon.battle.end.stockpile": "%1$s's stockpiled effect wore off!",
"cobblemon.battle.end.infestation": "%1$s was freed from Infestation!",
"cobblemon.battle.block.sweetveil": "%1$s can't fall asleep due to a veil of sweetness!",
"cobblemon.battle.block.uproar": "But the uproar kept %1$s awake!",
@@ -2147,9 +2142,15 @@
"cobblemon.battle.terastallize": "%1$s has Terastallized into the %2$s-type!",
"cobblemon.battle.detailschange.mega": "%1$s is reacting to the Key Stone!",
"cobblemon.battle.detailschange.noice": "%1$s transformed!",
"cobblemon.battle.detailschange.eiscue": "%1$s transformed!",
"cobblemon.battle.formechange.default.permanent": "%1$s transformed into its %2$s form!",
"cobblemon.battle.formechange.default.temporary": "%1$s changed to its %2$s form!",
"cobblemon.battle.formechange.default.temporary.ended": "%1$s changed to its base form.",
"cobblemon.battle.formechange.mega": "%1$s is reacting to the Key Stone!",
"cobblemon.battle.formechange.ash": "%1$s became Ash-Greninja!",
"cobblemon.battle.formechange.school": "%1$s formed a school!",
"cobblemon.battle.formechange.wishiwashi": "%1$s stopped schooling!",
"cobblemon.battle.formechange.meteor": "%1$s shielded itself.",
"cobblemon.battle.formechange.minior": "%1$s stopped shielding itself.",
"cobblemon.battle.mega": "%1$s has Mega Evolved!",
@@ -6776,7 +6777,7 @@
"cobblemon.ability.schooling": "Schooling",
"cobblemon.ability.schooling.desc": "When it has a lot of HP, the Pokémon forms a powerful school. It stops schooling when its HP is low.",
"cobblemon.ability.scrappy": "Scrappy",
"cobblemon.ability.scrappy.desc": "The Pokémon can hit Ghost-type Pokémon with Normal- and Fighting-type moves.",
"cobblemon.ability.scrappy.desc": "The Pokémon can hit Ghost-type Pokémon with Normal- and Fighting-type moves. It also grants immunity to Intimidate.",
"cobblemon.ability.screencleaner": "Screen Cleaner",
"cobblemon.ability.screencleaner.desc": "When the Pokémon enters a battle, the effects of Light Screen, Reflect, and Aurora Veil are nullified for both opposing and ally Pokémon.",
"cobblemon.ability.seedsower": "Seed Sower",

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