Compare commits

...
308 Commits
Author SHA1 Message Date
Paul 765e9f2cc3 snapshot = false 2023-12-23 11:39:57 +10:00
Paul ffda34742c Edge case protection with nickname migration 2023-12-23 11:01:03 +10:00
Paul c2385edbe7 more more changelog [skip-ci] 2023-12-23 11:00:00 +10:00
Paul 961ad0f4bd more changelog [skip-ci] 2023-12-23 10:45:07 +10:00
Paul 8851594347 Changelog polishing and removing stacks of unused item files 2023-12-23 10:44:32 +10:00
Paul 3c1ad2bea6 Add pokeball vivillon variant back into advancement 2023-12-23 09:10:17 +10:00
Hiroku e1960792d7 Merge branch 'bush_pathing' into 'main'
Berry bush avoidance

See merge request cable-mc/cobblemon!824
2023-12-22 22:50:24 +00:00
gr3ger 23b9f933c7 Updated changelog. 2023-12-22 23:37:27 +01:00
Paul 9662699bcb Fix mongo adapter constructor issue 2023-12-23 08:29:54 +10:00
Hiroku 32b2d2023b Merge branch 'nickname-migrate' into 'main'
Adds json nickname migrate + bug fix for non player entity backed battle actors.

See merge request cable-mc/cobblemon!821
2023-12-22 22:24:03 +00:00
Hiroku c64612859c Merge branch '732_spelling' into 'main'
Fix wrong name on animation/model folders

Closes #732

See merge request cable-mc/cobblemon!822
2023-12-22 22:17:12 +00:00
gr3ger 6c97c4c238 Removed extra call to getBlockState() and made function return on match instead of going through all if statements. 2023-12-22 23:11:58 +01:00
gr3ger 6535d43964 PoC bush avoidance 2023-12-22 18:16:21 +01:00
gr3ger 234d1dad44 Closes #732
Tested spawning entities after changes, nothing seems out of the ordinary.
2023-12-22 10:12:47 +01:00
Deltric da247e9902 Adds json nickname migrate + bug fix for non player entity backed battle actors. 2023-12-22 01:47:19 -06:00
Paul 0655d63dc5 Removed a couple of recipe advancements that are for items not ingame 2023-12-22 12:06:23 +10:00
Paul 81ba5ef615 Removed errant "light powder" item 2023-12-22 10:53:59 +10:00
Paul 8354c3838a Merge remote-tracking branch 'origin/main' 2023-12-22 10:10:12 +10:00
Paul 80db305aba Updated heaps of langs from crowdin 2023-12-22 10:10:00 +10:00
Hiroku 60e0314f29 Merge branch 'Spawn_Level_Scaling' into 'main'
Level scaling tweak

See merge request cable-mc/cobblemon!820
2023-12-19 22:14:21 +00:00
Nick 5f868630e0 Merge branch 'neo-bounties' into 'main'
:)

See merge request cable-mc/cobblemon!818
2023-12-19 20:46:10 +00:00
MoeBoy76 b93adae945 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into Spawn_Level_Scaling
# Conflicts:
#	CHANGELOG.md
2023-12-19 12:49:57 +11:00
MoeBoy76 9f1ed344d8 Changelog 2023-12-19 12:46:48 +11:00
MoeBoy76 2c256eefde Correct logic and cleanup unused test code 2023-12-19 12:27:41 +11:00
Neovitalism b075fce83f :)
#725 - Adds a boolean property to PokemonEntity to make it not count towards the spawn cap.
#728 - Makes PokemonEntity respect minecraft's silent flag.
2023-12-18 15:10:19 -06:00
Paul f2ed332c4c Fixed minor error in lang 2023-12-19 05:51:00 +10:00
Paul e8f083d8bf Merge remote-tracking branch 'origin/main' 2023-12-19 05:50:38 +10:00
Hiroku 1684a341a1 Merge branch 'Swim_Behavior_Fix' into 'main'
Fixed Swim Behaviors for some Pokemon

See merge request cable-mc/cobblemon!817
2023-12-18 19:40:34 +00:00
Hiroku b4e1bf794d Merge branch 'Pokemon_Weight_Watchers' into 'main'
Changed calculations of Pokemon's weight and height before it is sent to Showdown so that battle damage for weight-based moves are accurate

See merge request cable-mc/cobblemon!816
2023-12-18 19:40:22 +00:00
jeffw773 c85ad7d60c - Changelog 2023-12-18 11:28:53 -08:00
jeffw773 e61e92a5d4 - Changelog 2023-12-18 11:27:08 -08:00
jeffw773 a245e9661c - final tweaks for MR 2023-12-18 11:01:35 -08:00
jeffw773 059152b34c - removed unused test code 2023-12-18 10:58:59 -08:00
jeffw773 0d35157fcf - removed unused test code 2023-12-18 10:42:43 -08:00
jeffw773 302388d0a6 - Added Swim behaviors to Samurott line, Clodsire, Wimpod, Golisopod, Quaxwell, Quaquaval, 2023-12-18 10:30:07 -08:00
jeffw773 ab957f82e1 - Altered some code for how Pokemon's height and weight is calculated for weight-based moves during battles as it had issues and was doing more damage than it should have been 2023-12-17 20:18:41 -08:00
jeffw773 fef82ae6bf - Altered some code for how Pokemon's height and weight is calculated for weight-based moves during battles as it had issues and was doing more damage than it should have been 2023-12-17 20:16:06 -08:00
jeffw773 8b979c1944 - Altered some code for how Pokemon's height and weight is calculated for weight-based moves during battles as it had issues and was doing more damage than it should have been 2023-12-17 19:52:32 -08:00
Paul 4bbbaacacf Merge remote-tracking branch 'origin/main' 2023-12-18 08:34:34 +10:00
jeffw773 eda8e15509 Merge remote-tracking branch 'origin/main' 2023-12-17 10:03:21 -08:00
Nick d53a71c188 Merge branch '1.4.1-fixes' into 'main'
1.4.1 fixes

See merge request cable-mc/cobblemon!814
2023-12-17 01:16:44 +00:00
Hiroku d2f02b0d06 1.4.1 fixes 2023-12-17 01:16:44 +00:00
Paul 5c0bb194b6 Fixed Tyrogue fainting into the floor 2023-12-17 10:50:08 +10:00
Paul e41562f5ad Fixed status apply fail messages for when they're already afflicted by that status 2023-12-17 10:49:59 +10:00
Paul 69ea1ac3bf Fixed things like Keen Eye not having translation stuff 2023-12-17 10:29:19 +10:00
Paul 7c15f0f924 Fixed confusing poison heal messages 2023-12-17 09:40:32 +10:00
Paul 6165e5e871 Corrected mistaken changelog entry 2023-12-17 09:19:41 +10:00
Paul dd8f59e0d0 Removed pink bow recipe as not needed anymore 2023-12-17 09:11:56 +10:00
Paul 87611795e9 Fixed battle messages getting out of sync after spectating, unspectating, re-spectating 2023-12-17 09:11:18 +10:00
Paul d2fe9b1132 Fixed Life Orb not having a proper item name 2023-12-17 08:57:26 +10:00
Hiroku e95759a710 Merge branch 'whatsy/bugfixes' into 'main'
Various bugfixes for 1.4.1

Closes #722 and #724

See merge request cable-mc/cobblemon!805
2023-12-16 21:50:39 +00:00
Hiroku 7284f8d35d Merge branch 'can-moe-scrape' into 'main'
Teal Mask species data

See merge request cable-mc/cobblemon!806
2023-12-16 21:24:07 +00:00
Hiroku 334dd1206e Merge branch 'share-the-explove' into 'main'
Balanced EXP Share Recipe

Closes #727

See merge request cable-mc/cobblemon!811
2023-12-16 21:23:32 +00:00
Hiroku e7caab0ae0 Merge branch 'Waldleufer/spawnCSVScriptPolishing' into 'main'
minor spawn CSV Script improvements and pokemon.json fix

See merge request cable-mc/cobblemon!812
2023-12-16 21:22:58 +00:00
Waldleufer 47f02f6e50 Restored Script default settings 2023-12-16 11:42:31 +01:00
Waldleufer 3367b0c39c dissolved bug in script
that would occur if the filled out Multiplier column for one pokemon was followed by an empty field
2023-12-16 11:40:47 +01:00
Waldleufer 0e43d7730c verified omanyte, omastar kabuto and kabutops json 2023-12-16 11:07:06 +01:00
Waldleufer b5604686f2 fix: Updated all minecraft:nether_quartz to minecraft:quartz 2023-12-16 11:05:00 +01:00
Waldleufer e030dbfbf5 refactor: Made the script report more readable. 2023-12-16 11:03:56 +01:00
Lily 96647a9398 fix conflict in changelog 2023-12-15 19:09:58 +00:00
dhi_holo 9e2c0ab0db Balanced EXP Share Recipe
Closes #727
2023-12-14 06:48:43 +10:00
Lily 1bc953f3f3 lang update 2023-12-12 14:40:06 +00:00
jeffw773 d089eab60f - Start of a tweak to how spawns work in terms of scaling the level of Pokémon based off of player party highest level 2023-12-11 17:19:19 -08:00
Hiroku d18cab39a9 Merge branch 'kkeenanwong-main-patch-46161' into 'main'
Update garganacl.json quartz item ID

See merge request cable-mc/cobblemon!808
2023-12-11 03:21:09 +00:00
Keenan Wong 4492666f5a Update garganacl.json quartz item ID 2023-12-11 03:04:33 +00:00
Hiroku 6a0985958b Merge branch 'reknot' into 'main'
Knot Flip

See merge request cable-mc/cobblemon!807
2023-12-10 23:37:43 +00:00
dhi_holo 308c5e6d32 Knot Flip
Destiny Knot recipe has been vertically flipped, to closer match the sprite.
2023-12-11 09:15:40 +10:00
MoeBoy76 bd83cc143b redo broken é 2023-12-09 23:43:12 +11:00
MoeBoy76 c9e6cb1022 fix line separator 2023-12-09 23:40:43 +11:00
MoeBoy76 74c75b7faa Applin evo data 2023-12-09 23:31:52 +11:00
MoeBoy76 45819a17f6 Teal Mask new data 2023-12-09 22:36:32 +11:00
Lily e3f84248b8 Added StructureLikeCondition.kt and a new StructureRequirement for evolutions. Closes #722 2023-12-05 19:35:30 -05:00
Lily 0ff518194f Fix grammar errors on certain pokeballs. made small fixes to Vivillon evolutions. Closes #724 2023-12-05 18:42:58 -05:00
Lily 634a1ad6fc Fixed Inkay evolution, fixed conflicting biome requirements for ocean, river, sun, and tundra vivillion variants. Closes #724 2023-12-05 16:58:39 +00:00
Lily 41217ebdcc Remove poke ball variant from the Vivillionaire advancement 2023-12-05 16:42:05 +00:00
Hiroku a021ec1337 Merge branch 'sound' into 'main'
Fixed missing cries again

See merge request cable-mc/cobblemon!803
2023-12-04 20:30:00 +00:00
Sterrezo b03f95b7da Fixed missing cries again
Scatterbug and Spewpa lost their cries somewhere so I re-added them. No changelog because this happened during development, so it's as it was in 1.4
2023-12-04 17:55:26 +01:00
Paul d8cee44661 Changelog [skip-ci] 2023-12-02 14:56:45 +10:00
Hiroku 5dd2287441 Merge branch 'fastutil-crash' into 'main'
Fixed fastutil crash

See merge request cable-mc/cobblemon!802
2023-12-02 04:39:25 +00:00
Paul 1eb6af14c2 Changelog 2023-12-02 10:53:18 +10:00
Paul 61b73972d4 Merge branch '1.4.0a'
# Conflicts:
#	CHANGELOG.md
2023-12-02 10:39:31 +10:00
Hiroku f8bcf8c291 Merge branch 'rendercontext-additions' into 'main'
Add species and aspects to RenderContext

See merge request cable-mc/cobblemon!799
2023-12-02 00:28:20 +00:00
Waterpicker 543d408e63 Merge remote-tracking branch 'cable-mc/main' into rendercontext-additions 2023-12-01 00:46:35 -06:00
Apion 2cdc781e93 Merge branch 'battles-unlanguished' into 'main'
Added langs and update interpreter

See merge request cable-mc/cobblemon!801
2023-12-01 05:45:42 +00:00
Segfault Guy 8dc0a7f72d Interpreter trimmings and fixes. 2023-12-01 00:18:50 -05:00
Paul 8b5231d6f0 Alternative way to fix dupe issue to not crash (huge) 2023-12-01 12:07:00 +10:00
Hiroku 665c4cc26c Merge branch 'particle-command' into 'main'
Added /bedrockparticle command

See merge request cable-mc/cobblemon!798
2023-11-30 22:50:25 +00:00
apion 7c860d8f91 Fix some of seg's review threads 2023-11-30 12:39:09 -05:00
apion 006e86f3c3 Fix my review threads 2023-11-30 11:37:52 -05:00
MoeBoy76 91dec859e8 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into battles-unlanguished
# Conflicts:
#	CHANGELOG.md
2023-11-30 11:55:53 +11:00
Apion 85f08c9d28 Merge branch 'regionalise' into 'main'
Regionalise

See merge request cable-mc/cobblemon!800
2023-11-30 00:51:21 +00:00
MoeBoy76 d465f465c8 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into battles-unlanguished
# Conflicts:
#	CHANGELOG.md
2023-11-30 11:43:02 +11:00
MoeBoy76 a87bd35fd6 changelog time 2023-11-30 11:38:39 +11:00
MoeBoy76 0c32da0ce1 added species feature for all regional forms that were missing it 2023-11-30 08:51:54 +11:00
Waterpicker 2bdb110c92 Remove some debug code I missed! 2023-11-29 14:04:20 -06:00
Waterpicker d21f3747fc Add species and aspects to RenderContext 2023-11-29 13:56:53 -06:00
jeffw773 fb303fcd97 - Started basic functionality of Battle menu that can be controlled by WASD or keybinded keys. Still more todo on this, but wanted to make a branch for it now 2023-11-29 11:35:50 -08:00
jeffw773 31b185b96c - Added -endability and -transform handlers 2023-11-28 00:06:52 -08:00
jeffw773 034a51b904 Merge remote-tracking branch 'origin/battles-unlanguished' into battles-unlanguished 2023-11-27 22:12:01 -08:00
jeffw773 9e1c491d9c - Moe said it was okay 2023-11-27 22:11:42 -08:00
jmmcp f695a99705 Added -swapboost langs for Guard Swap, Power Swap, and Heart Swap, as well as -start lang for Tar Shot. 2023-11-28 00:31:13 -05:00
jmmcp a8567f9190 Added check for optional effects in handleStartInstruction to allow for proper handling of moves like Reflect Type. 2023-11-27 23:39:27 -05:00
jmmcp 7d455b2dac Merge remote-tracking branch 'origin/battles-unlanguished' into battles-unlanguished
# Conflicts:
#	common/src/main/resources/assets/cobblemon/lang/en_us.json
2023-11-27 23:10:57 -05:00
jmmcp 1dffbd1b37 Added -start langs for embargo and general typeadd moves. 2023-11-27 23:10:10 -05:00
jeffw773 332e25fa76 Merge remote-tracking branch 'origin/battles-unlanguished' into battles-unlanguished 2023-11-27 20:07:53 -08:00
jeffw773 f080fb5639 - Added Substitute Start Language 2023-11-27 20:07:34 -08:00
jmmcp 769a1862e4 Added -copyboost lang, new copyboost instruction handler, new copy method to ContextManager, silent optional argument check to -clearnegativeboost instruction handler, and tweaked -enditem instruction handler in CobblemonHeldItemManager to allow for cases with null source (example: Fling). 2023-11-27 22:25:54 -05:00
jmmcp 127c5e7a8b Merge branch 'main' into battles-unlanguished 2023-11-27 19:11:22 -05:00
Paul d1a71373c0 Added /bedrockparticle command 2023-11-27 13:26:26 +10:00
Hiroku 77def6de43 Merge branch 'mooshtank_fix_and_shuckle_nerf' into 'main'
Shuckle Berry Nerf + Brown Mooshtank Sus Stew Fix

See merge request cable-mc/cobblemon!792
2023-11-27 01:42:01 +00:00
jmmcp 973c6bb05f Merge remote-tracking branch 'origin/battles-unlanguished' into battles-unlanguished 2023-11-26 19:39:26 -05:00
jmmcp 5b83e49669 Added -start lang for type changing moves Camouflage, Conversion, and Conversion2, as well as -sidestart and -sideend langs for Lucky Chant and Mist. 2023-11-26 19:38:59 -05:00
Hiroku e01bc2eeab Merge branch 'nickname_invalid_format' into '1.4.0'
Resolves a bug in the format in which the nickname is saved in JSON.

See merge request cable-mc/cobblemon!797
2023-11-26 23:19:50 +00:00
Pedro Souza f6f3070b8e changelog 2023-11-26 20:18:37 -03:00
Pedro Souza 0f2301e668 Resolved nickname invalid format bug 2023-11-26 12:24:54 -03:00
jeffw773 80ce5bab58 - Added battle language for powertrick and powershift 2023-11-26 01:25:15 -08:00
Hiroku 8fb678b0f8 Merge branch 'battle_music_enhancements' into 'main'
Add new battle music features

Closes #587

See merge request cable-mc/cobblemon!790
2023-11-26 08:17:45 +00:00
jeffw773 c0a77aca23 - Added battle language for Stockpile 2023-11-26 00:02:37 -08:00
jmmcp e4c0eab8e2 Added -fieldactivate langs for Fairy Lock and Teatime, as well as a new handler for -invertboost instructions. 2023-11-26 00:02:04 -05:00
Hiroku b9ff46e1b2 Merge branch 'sirrfuchs-main-patch-53627' into 'main'
Added canFly true to Yveltal

See merge request cable-mc/cobblemon!796
2023-11-25 21:22:45 +00:00
sirrfuchs 45a998d3d7 Added canFly true to Yveltal 2023-11-25 16:27:57 +00:00
Hiroku a108d85531 Merge branch 'root-burn' into 'main'
Remedy Alternate Cooking

See merge request cable-mc/cobblemon!795
2023-11-25 07:22:27 +00:00
dhi_holo 0fae45f811 Remedy Alternate Cooking
Smokers and Campfires work now
2023-11-25 10:13:19 +10:00
Hiroku 88717d598d Merge branch 'Waldleufer/speciesJsonFixes' into 'main'
small species json fixes

See merge request cable-mc/cobblemon!794
2023-11-24 22:14:28 +00:00
Waldleufer 33123b4a33 small species json fixes 2023-11-24 22:14:27 +00:00
Hiroku 74e0915ec8 Merge branch 'SmarterDrops' into 'main'
Corrected some drops, added missing drops to a bunch of base forms and forms.

See merge request cable-mc/cobblemon!789
2023-11-24 00:00:28 +00:00
Waldleufer 39cd5e9726 Corrected some drops, added missing drops to a bunch of base forms and forms. 2023-11-24 00:00:28 +00:00
jeffw773 876be2afcf - Brown Mooshtanks give Suspicious Stews like vanilla brown mooshrooms do (plus Pep Up Flower)
- Nerfed Infinite Berry Juice Shuckle
2023-11-22 19:07:39 -08:00
jeffw773 d693f452bc - Fixed Mooshtanks not giving mushroom stew in creative
- Nerfed Shuckle infinite Berry Juice
2023-11-22 15:49:54 -08:00
jmmcp a1e94b8200 Added -activate langs for eerie spell and crafty shield. 2023-11-22 01:04:11 -05:00
Segfault Guy 8b4552a532 Unique wild encounter themes. 2023-11-19 22:33:26 -05:00
Segfault Guy 41673ba90f Battle music for spectators. 2023-11-19 22:33:26 -05:00
Segfault Guy 18f9942dc6 BattleStartedEvent rework and battle music override support. 2023-11-19 22:33:23 -05:00
Segfault Guy 875fe46d21 Player specific battle themes. 2023-11-19 22:32:42 -05:00
Segfault Guy 66c6f9bdd1 BattleMusicHandler upgrades and bug fixes. 2023-11-19 22:32:04 -05:00
Hiroku b72af84c8c Merge branch 'tooltip-fix' into 'main'
Tooltip fix

See merge request cable-mc/cobblemon!788
2023-11-20 00:32:18 +00:00
miasmus a5ee270b8b account for tooltips with only 1 element 2023-11-19 19:00:05 -05:00
miasmus c08ef4247d doing it this way cause the other way was bad 2023-11-19 18:24:47 -05:00
jmmcp 9424bafabb Merge remote-tracking branch 'origin/battles-unlanguished' into battles-unlanguished 2023-11-19 18:21:02 -05:00
jmmcp a96ecfcdf2 Added -fail instructions for Burn Up and Double Shock, as well as lang for healing moves and weight based moves against Dynamaxed mons failing 2023-11-19 18:20:07 -05:00
Hiroku b1d11e8c22 Merge branch 'HOLDY2' into 'main'
Fixed some minor errors in the newly added dropps

See merge request cable-mc/cobblemon!787
2023-11-19 22:05:02 +00:00
Waldleufer c1fb1379a9 Fixed some minor errors in the newly added dropps 2023-11-19 22:05:02 +00:00
Hiroku 5a220e0ef0 Merge branch 'implement_pokemon' into 'main'
Implemented Drifloon line and minor asset updates.

See merge request cable-mc/cobblemon!786
2023-11-19 22:01:03 +00:00
Hiroku b379fc62b1 Merge branch 'Waldleufer/cry_checker_script' into 'main'
cry audio checker script

See merge request cable-mc/cobblemon!785
2023-11-19 21:55:53 +00:00
Waldleufer d442e4e956 cry audio checker script 2023-11-19 21:55:53 +00:00
Tyzillion bb22c22db9 added "implemented": true to the species.json for the new Pokemon implemented. 2023-11-19 10:33:58 -05:00
JazzMcNade 09bc174401 Added code to display enditem.incinerate's message when it occurs. 2023-11-19 04:26:13 -06:00
Tyzillion e109a1d59f Implemented Drifloon line, Updated Dodrio textures, updated aegislash_shiny texture, Updated models for Geodude line. Added emissives for Noctowl. 2023-11-18 22:12:23 -05:00
jmmcp 3b97a0c847 Added -activate langs for Skill Swap and Wide Guard, -enditem langs for Corrosive Gas and Bug Bite, -fail lang for Aura Wheel, and allow for effectID to pass through as null in handle fail instruction for fails that don't have an effect, such as Baton Pass and Bide. 2023-11-18 16:02:58 -05:00
JazzMcNade 87e8fcd7f7 Added -end lang for Healblock and Skydrop. Added -fail for Skydrop 2023-11-17 22:47:41 -06:00
Hiroku b34f8a045d Merge branch 'null-safety-time' into 'main'
Fix to NullPointerException in PokemonOnShoulderHandler

Closes #677

See merge request cable-mc/cobblemon!783
2023-11-18 04:26:38 +00:00
JPAKx4 4f79b9f8a7 Fix to https://gitlab.com/cable-mc/cobblemon/-/issues/677 2023-11-17 21:30:49 -06:00
JazzMcNade d1b651a876 Added -activate langs for Grudge, Speedswap and Switcheroo. 2023-11-17 21:13:55 -06:00
Hiroku b30a67651e Merge branch 'VillagerCropInteractionFix' into 'main'
Fix for villagers not being able to pick and plant mint seeds, vivichoke seeds...

Closes #647

See merge request cable-mc/cobblemon!760
2023-11-18 01:43:10 +00:00
JazzMcNade a1398e9495 Fixed capitalization. 2023-11-17 19:22:42 -06:00
jmmcp ca319764f0 Added -activate langs for Ingrain, Mist, Poltergeist, Powder, Quash, Quick Guard, Safeguard, and Sketch. 2023-11-17 19:00:12 -05:00
Hiroku ac03c68f41 Merge branch 'defaultIssueTemplate' into 'main'
Added a default Issue Template

See merge request cable-mc/cobblemon!769
2023-11-17 22:16:35 +00:00
Nick 0eb4b43b49 Merge branch 'updated-showdown' into 'main'
Updated Showdown version to latest master from Smogon

Closes #542

See merge request cable-mc/cobblemon!764
2023-11-17 21:18:05 +00:00
Hiroku b49376dba5 Updated Showdown version to latest master from Smogon 2023-11-17 21:18:03 +00:00
Nick 81f6e7b786 Merge branch 'shuckle_milk' into 'main'
Added ability for Shuckles to be milked for Berry Juice

See merge request cable-mc/cobblemon!770
2023-11-17 21:17:28 +00:00
Plastered_Crab 574ee1ae4a Added ability for Shuckles to be milked for Berry Juice 2023-11-17 21:17:27 +00:00
Nick 07a83f54a2 Merge branch 'HOLDY-lite' into 'main'
It's holding time

See merge request cable-mc/cobblemon!777
2023-11-17 19:41:59 +00:00
Jordan 6f3b530d7b It's holding time 2023-11-17 19:41:59 +00:00
Nick 4b86dc1e58 Merge branch 'ability-optional-arguments' into 'main'
Implement method to properly handle showdown ability instructions with optional arguments.

Closes #499

See merge request cable-mc/cobblemon!778
2023-11-17 19:30:45 +00:00
JMMCP bb141aee50 Implement method to properly handle showdown ability instructions with optional arguments. 2023-11-17 19:30:45 +00:00
Nick acb473c01f Merge branch 'Waldleufer/fixUndergroundSpawningAlgorithm' into 'main'
Underground Spawning Algorithm Improvements

See merge request cable-mc/cobblemon!737
2023-11-17 18:37:02 +00:00
Waldleufer a8dc3f40a4 Underground Spawning Algorithm Improvements 2023-11-17 18:37:02 +00:00
Nick b55f11628d Merge branch 'Waldleufer/spawnSpreadsheetToCodeAutomation' into 'main'
Validated and corrected all Spawnfiles

See merge request cable-mc/cobblemon!755
2023-11-17 18:27:17 +00:00
Waldleufer 150c03d4f5 Validated and corrected all Spawnfiles 2023-11-17 18:27:17 +00:00
Nick 1c092588f4 Merge branch 'HealingWishUnfaintPostBattleFix' into 'main'
HealingWishUnfaintPostBattleFix

See merge request cable-mc/cobblemon!779
2023-11-17 18:19:11 +00:00
JazzMcNade 683473c34c - Added activate.electricterrain 2023-11-17 02:43:36 -06:00
jeffw773 c7dee1bd53 - Added some more -start flags 2023-11-16 23:00:03 -08:00
jeffw773 d83a1086d3 - Added start.futuresight 2023-11-16 22:17:35 -08:00
Hiroku b34ca3d42b Merge branch 'HealthBarUpdateOnDamageFix' into 'main'
Fix for health bars not updating when a pokemon takes damage from commit 132a43c5

See merge request cable-mc/cobblemon!775
2023-11-17 05:04:34 +00:00
MoeBoy76 3a1389d719 start of missing battle messages 2023-11-17 10:18:44 +11:00
Hiroku e608dc84ae Merge branch 'mongodb-timestamp' into 'main'
Added timestamp to MongoDB store to signify when the save was created.

See merge request cable-mc/cobblemon!781
2023-11-16 14:49:52 +00:00
navneetset c987a5ba19 Added timestamp to MongoDB store to signify when the save was created. 2023-11-16 14:08:18 +01:00
Hiroku d65090ce10 Merge branch 'main' into 'main'
Issue #699 - Fixed typo in Coba Berry tooltip.

See merge request cable-mc/cobblemon!780
2023-11-16 11:09:45 +00:00
Michael 206ec25a99 Issue #699 - Fixed typo in Coba Berry tooltip. 2023-11-16 03:22:47 -05:00
JazzMcNade ccd376c055 Refactoring 2023-11-14 22:19:40 -06:00
JazzMcNade 6214fb1b97 The handleDamageInstruction inner dispatch is now placed at the head of the queue to make sure it stays ahead of the handleFaintInstruction dispatch. 2023-11-13 01:13:27 -06:00
JazzMcNade a65cee3e24 Fix for health bars not updating when a pokemon takes damage from commit 132a43c5 2023-11-13 00:51:50 -06:00
Hiroku 9999a04692 Merge branch 'status-complete' into 'main'
added tab completion for Statuses

See merge request cable-mc/cobblemon!774
2023-11-13 06:29:19 +00:00
MoeBoy76 6901f3e43d added tab completion for Statuses 2023-11-13 17:07:22 +11:00
Waldleufer 1a0135c1fd Added a feature request issue template. 2023-11-12 10:25:44 +01:00
Waldleufer 23dab6546f Added requested changes 2023-11-12 10:25:16 +01:00
Hiroku 3b94b6660c Merge branch 'new_battle_fix' into 'main'
New 100+ Battle languages fixed

See merge request cable-mc/cobblemon!771
2023-11-12 08:55:05 +00:00
jeffw773 dc46c96ecf Fixed merge conflicts 2023-11-12 00:33:00 -08:00
Hiroku 55861a249e Merge branch 'augh-u-rite' into 'main'
More Augurite Usage

Closes #687

See merge request cable-mc/cobblemon!754
2023-11-12 03:28:42 +00:00
Hiroku f00a569d9d Merge branch 'main' into 'augh-u-rite'
# Conflicts:
#   CHANGELOG.md
2023-11-12 02:40:29 +00:00
Hiroku aaa5484752 Update CHANGELOG.md [skip-ci] 2023-11-12 01:38:44 +00:00
Hiroku c6e82ebfb9 Merge branch 'fix-405-recall-visual-bug' into 'main'
Fix visual Pokemon recall bug

Closes #415 and #405

See merge request cable-mc/cobblemon!750
2023-11-12 01:37:19 +00:00
Hiroku 365844ae2e Merge branch 'battle_text_fail_block' into 'main'
Added -fail and -block handlers to ShowdownInterpreter as well as added around...

See merge request cable-mc/cobblemon!753
2023-11-12 01:33:22 +00:00
Hiroku c18c1f39fb Merge branch 'main' into 'battle_text_fail_block'
# Conflicts:
#   CHANGELOG.md
2023-11-12 01:09:42 +00:00
Hiroku 1fd2aa06ae Merge branch 'EXP-Item-Pokemon-Select' into 'main'
Exp Candies - Party Pokemon Select

Closes #692

See merge request cable-mc/cobblemon!757
2023-11-11 22:55:31 +00:00
Hiroku 931852bd36 Merge branch 'alolanRatataFix' into 'main'
Fixed alolan Rattata animations

Closes #695

See merge request cable-mc/cobblemon!768
2023-11-11 19:48:25 +00:00
Waldleufer 272f429f59 Fixed alolan Rattata animations 2023-11-11 19:48:24 +00:00
Waldleufer b4787b8db8 Added a default Issue Template 2023-11-11 19:44:02 +01:00
Hiroku 6a5c6d2b17 Merge branch 'licious/190' into 'main'
Conditional held item consumption

Closes #190

See merge request cable-mc/cobblemon!767
2023-11-11 12:37:16 +00:00
Hiroku 618453caaa Update CHANGELOG.md 2023-11-11 11:53:18 +00:00
Hiroku e1d048ec9d Merge branch 'main' into 'licious/190'
# Conflicts:
#   CHANGELOG.md
2023-11-11 11:52:37 +00:00
Hiroku 26ebd23d14 Merge branch 'sound' into 'main'
Added cries to the Beldum line, tweaked Pikachu and Raichu cries

See merge request cable-mc/cobblemon!766
2023-11-11 01:07:05 +00:00
Paul b446415200 Fixed minor position error in new pokeball animations 2023-11-11 09:45:47 +10:00
jeffw773 ed8fe19dc1 Fixed redundancies, added shared langs for a few moves, and fixed red formatting for fail lang. 2023-11-10 15:30:11 -08:00
Hiroku cdcc071ce0 Merge branch 'main' into 'VillagerCropInteractionFix'
# Conflicts:
#   CHANGELOG.md
2023-11-10 22:51:44 +00:00
dhi_holo e674b042d0 Nerfed Obsidian
reduced crafting to output 1 because it makes more sense
2023-11-11 08:49:21 +10:00
dhi_holo 53abb58ae6 Merge branch 'main' into augh-u-rite 2023-11-11 08:47:01 +10:00
Sterrezo 17fed9662c Merge branch 'main' into sound 2023-11-10 21:38:28 +01:00
Sterrezo 74dd2a6c0d Added cries to the Beldum line, tweaked Pikachu and Raichu cries 2023-11-10 21:38:11 +01:00
Stephen White 7505ce15e3 Merge remote-tracking branch 'upstream/main' into fix-405-recall-visual-bug 2023-11-10 12:27:43 -04:00
Charzard4261 30ba97ea69 Merge remote-tracking branch 'origin/EXP-Item-Pokemon-Select' into EXP-Item-Pokemon-Select 2023-11-10 14:15:20 +00:00
Charzard4261 5fee2df9f7 Added a missing POKEMON_INTERACT trigger in PokemonSelectingItem, when successfully using an Item on a Pokemon out of battle. 2023-11-10 14:14:53 +00:00
Charzard4261 238c7474b3 Merge branch 'main' into 'EXP-Item-Pokemon-Select'
# Conflicts:
#   CHANGELOG.md
2023-11-10 11:14:39 +00:00
Hiroku 5da5c72b4f Merge branch 'main' into 'main'
Restored Fabric BrewingStandBlockEntityMixin for brewing stand/sidehopper interaction

See merge request cable-mc/cobblemon!746
2023-11-10 05:55:58 +00:00
Hiroku 0604b45b9d Merge branch 'spectate' into 'main'
Added ability to spectate pokemon battles

See merge request cable-mc/cobblemon!747
2023-11-10 05:28:50 +00:00
Apion 132a43c5c7 Added ability to spectate pokemon battles 2023-11-10 05:28:50 +00:00
Hiroku b1e8f9cfb6 Merge branch 'fortune_evo_ores' into 'main'
Fortune evo ores

Closes #686

See merge request cable-mc/cobblemon!765
2023-11-10 04:21:57 +00:00
Lily a166a38c4b Update CHANGELOG.md 2023-11-09 22:59:52 -05:00
Lily 57fa6a58d5 Add Fortune compatibility to evo stone ores. Closes #686 2023-11-09 22:58:39 -05:00
Charzard4261 95006ae327 Merge branch 'main' into 'EXP-Item-Pokemon-Select'
# Conflicts:
#   CHANGELOG.md
2023-11-10 00:08:03 +00:00
Hiroku ad6fc97eef Merge branch 'implement_pokemon' into 'main'
One new Pokémon line, Animation, Textures, and Models updated. Pokémon Sleep? Naw just sleepy Pokemon.

See merge request cable-mc/cobblemon!763
2023-11-10 00:03:21 +00:00
Tyzillion fc39baaa30 Fixed Exeggcute faint, Added emissive to Hoothoot. 2023-11-09 18:40:59 -05:00
Tyzillion 887ff8ccdb Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2023-11-09 18:29:47 -05:00
Paul 4d6117f5bf Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2023-11-10 09:13:44 +10:00
Paul 3dc26639a5 Fixed Trevenant sleep animation 2023-11-10 09:13:28 +10:00
Tyzillion 252f9d5dbd Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon
# Conflicts:
#	CHANGELOG.md
2023-11-09 16:46:47 -05:00
Charzard4261 599b8c5eec Merge branch 'main' into 'EXP-Item-Pokemon-Select'
# Conflicts:
#   CHANGELOG.md
2023-11-09 18:55:55 +00:00
Nick 974f839d61 Merge branch 'more_composting' into 'main'
Update composting functionality for Heal Powder and mutated Herbs

Closes #681

See merge request cable-mc/cobblemon!759
2023-11-09 18:50:44 +00:00
Nick b4ea13ab20 Merge branch 'milk_the_mooshtank' into 'main'
Allow Mooshtanks to be milked for mushroom stew. Closes #684

Closes #684

See merge request cable-mc/cobblemon!758
2023-11-09 18:49:33 +00:00
Nick 06afb04050 Merge branch 'missing_messages' into 'main'
Added a bunch of missing texts. Fixes #582, #588

Closes #588 and #582

See merge request cable-mc/cobblemon!752
2023-11-09 18:48:25 +00:00
Lily 92c3d9464b Merge branch 'main' into milk_the_mooshtank
# Conflicts:
#	CHANGELOG.md
2023-11-09 13:04:53 -05:00
Lily 03ed8f3edd Update CHANGELOG.md 2023-11-09 13:03:23 -05:00
Hiroku b475b02fff Merge branch 'Bee-Related-Changes' into 'main'
Bee Related Changes

See merge request cable-mc/cobblemon!762
2023-11-08 20:10:18 +00:00
Charzard4261 8c462f1567 Gave the Pep-Up Flower item the "minecraft:flowers" tag, to allow Bees to be fed using them. 2023-11-08 16:23:16 +00:00
JazzMcNade 1c25ae69a5 Fix for villagers not being able to pick and plant mint seeds, vivichoke seeds and revival herbs. Closes #647 2023-11-08 03:05:03 -06:00
Lily e668735dd8 Update composting functionality for Heal Powder and mutated Herbs. Closes #681 2023-11-07 21:15:22 -05:00
Lily f0e65fe4de Allow Mooshtanks to be milked for mushroom stew. Closes #684 2023-11-07 20:41:19 -05:00
Charzard4261 084a7bfb3c CandyItem now uses PokemonSelectingItem, and does not consume when in Creative. 2023-11-08 00:46:51 +00:00
Tyzillion 3c11a673dc Update models for Hitmontop. Updated animations for Zubat, Golbat, Scatterbug, Spewpa. Added Shoulder animations for Zubat. 2023-11-07 07:23:36 -05:00
dhi_holo deb2cff477 A Use?
Augurite now can make axes and obsidian, closes #687
2023-11-07 12:16:30 +10:00
jeffw773 79d89852d4 Added -fail and -block handlers to ShowdownInterpreter as well as added around 17 battle texts related to them 2023-11-06 15:51:09 -08:00
Tyzillion 8d38144551 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon 2023-11-06 14:08:39 -05:00
Stephen White a21a172be3 Fix visual Pokemon recall bug 2023-11-06 10:32:05 -04:00
JazzMcNade b44e5c797e Made sure mixin logic is applied for all potion slots in brewing stands. 2023-11-05 17:12:15 -06:00
JazzMcNade ae9337c84a Mixin compatibility changes. 2023-11-05 16:33:44 -06:00
JazzMcNade 5db2c4c955 Restored BrewingStandBlockEntityMixin for brewing stand/hopper interaction 2023-11-05 03:59:54 -06:00
Hiroku 8af1225c90 Merge branch 'npc-revival' into 'main'
Prevent NPCs from freezing battles upon using Revival Blessing.

See merge request cable-mc/cobblemon!745
2023-11-05 05:14:51 +00:00
jmmcp 4b181d75c8 Added a check to avoid NPCs freezing battles upon using Revival Blessing. 2023-11-05 00:51:38 -04:00
Hiroku 9e28dce3d7 Merge branch 'revival-blessing-fix' into 'main'
Fixes the move Revival Blessing

Closes #660

See merge request cable-mc/cobblemon!744
2023-11-05 02:29:27 +00:00
jmmcp 39f084bd56 Can't forget the changelog. 2023-11-04 21:46:29 -04:00
jmmcp c82bba7872 Add checks throughout the switch process to allow the Revival Blessing forceSwitch command to validate. 2023-11-04 21:42:03 -04:00
Hiroku 3f557d9ae6 Merge branch 'return_bottles' into 'main'
Return bottles

Closes #674 and #673

See merge request cable-mc/cobblemon!742
2023-11-04 04:35:26 +00:00
Tyzillion c15976a936 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon
# Conflicts:
#	CHANGELOG.md
2023-11-03 21:38:04 -04:00
Hiroku c8652b519a Merge branch 'vivillon_wings' into 'main'
Implement new Vivillon patterns

Closes #600 and #676

See merge request cable-mc/cobblemon!743
2023-11-04 00:51:32 +00:00
Lily 67c828dd0c missed one 2023-11-03 19:49:30 -04:00
Lily 10a1bc6bc6 Merge remote-tracking branch 'origin/return_bottles' into return_bottles 2023-11-03 19:42:35 -04:00
Lily e4db065a85 change friendshop drop through json and not the item class 2023-11-03 19:42:09 -04:00
Hiroku 171cd45e32 Merge branch 'main' into 'return_bottles'
# Conflicts:
#   CHANGELOG.md
2023-11-03 23:27:57 +00:00
Lily d638315fb1 Rename "Patterned Wings" to "Vivillonaire". Closes #676 2023-11-03 19:27:38 -04:00
Hiroku 980fa6a13d Merge branch 'healing_percent_fix' into 'main'
Fix issue involving health display after healing

Closes #663

See merge request cable-mc/cobblemon!740
2023-11-03 23:27:37 +00:00
Hiroku 267faf9397 Merge branch 'get-nerfed' into 'main'
Harder Healing Machine, Nerds

Closes #672

See merge request cable-mc/cobblemon!741
2023-11-03 23:25:56 +00:00
Lily 7549d77ad7 Update CHANGELOG.md 2023-11-03 19:24:59 -04:00
Lily 0f6929dd5e implement new vivillon wing patterns. Closes #600 2023-11-03 19:23:18 -04:00
Licious 79597a81fe Implemented conditional held item consumption. 2023-11-03 11:44:42 +00:00
dhi_holo e54e822c3a Harder Healing Machine, Nerds
Closes #672
2023-11-03 15:12:30 +10:00
Lily 5e60bb525c Changes to healing items. Closes #673, #674 2023-11-02 23:47:12 -04:00
Tyzillion c49cb45892 Fixed sleeping animations not playing for many Pokmeon. Implemented Litwick line, Update model, texture, and animations for Zubat line. Fixed Ceruledge back spike texture error. Updated Dusknoir, Ratatta, and Exegguter animation. Fixed Volbeat t-pose when flying. Fixed Wimpod asymmetric eyebrows. Fixed Voltorb texture. Fixed shiny Pidgeotto texture. 2023-11-02 22:22:16 -04:00
Tyzillion e0a896377e Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon 2023-11-02 22:19:43 -04:00
Lily b96638226c Fixes #663 2023-11-02 22:19:36 -04:00
Lily 7c025582e0 Added a bunch of missing texts. Fixes #582, #588 2023-11-02 19:59:52 -04:00
Hiroku 623dfbb78b Merge branch 'licious/potion-fixes' into 'main'
Rework potion stuff & fixes

Closes #667 and #460

See merge request cable-mc/cobblemon!739
2023-11-02 23:28:37 +00:00
Licious 942bf8247e Consistent names aren't my specialty okay? 2023-11-02 22:44:26 +00:00
Licious d6a991e81e Fix various potion related issues. 2023-11-02 22:43:33 +00:00
Tyzillion 5d5de4f2f3 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon
# Conflicts:
#	CHANGELOG.md
2023-11-02 15:38:50 -04:00
Hiroku 7e952295a5 Merge branch 'licious/a-sign-of-boats-to-come' into 'main'
Implement Apricorn boats & signs

See merge request cable-mc/cobblemon!725
2023-11-02 08:14:26 +00:00
Hiroku d299cad9db Merge branch 'main' into 'licious/a-sign-of-boats-to-come'
# Conflicts:
#   CHANGELOG.md
2023-11-01 20:35:35 +00:00
Nick 261408d542 Merge branch 'licious/606' into 'main'
Progress related evolution requirement fixes

Closes #606

See merge request cable-mc/cobblemon!738
2023-11-01 19:01:24 +00:00
Nick cde163c1d1 Merge branch 'licious/597' into 'main'
Fix loot injection on Forge

Closes #597

See merge request cable-mc/cobblemon!736
2023-11-01 16:52:54 +00:00
Licious dbc478fc89 Fix battle critical hits evolution, fixed DamageTakenEvolutionProgress & DefeatEvolutionProgress not being registered. 2023-11-01 14:49:03 +00:00
Licious dde6c1dc97 *Apricorn 2023-10-31 23:47:46 +00:00
Licious 41d7740374 Merge branch 'main' into licious/a-sign-of-boats-to-come
# Conflicts:
#	CHANGELOG.md
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonItems.kt
#	common/src/main/resources/mixins.cobblemon-common.json
2023-10-31 23:44:21 +00:00
Licious 29f0c6f7bc Rework LootInjector functionality, fix Forge. 2023-10-31 23:38:17 +00:00
Licious d128d3e025 Merge branch 'blame-json' into 'main'
Advancements Fixed

See merge request cable-mc/cobblemon!735
2023-10-31 09:50:59 +00:00
Licious 422bd5a0de Merge branch 'licious/596' into 'main'
Add the Fairy Feather.

Closes #596

See merge request cable-mc/cobblemon!734
2023-10-31 09:50:28 +00:00
Licious 65271dc1b1 Merge branch 'licious/595' into 'main'
Add the Cleanse Tag item

Closes #595

See merge request cable-mc/cobblemon!733
2023-10-31 09:50:07 +00:00
dhi_holo 8a604fdefe Only Canon
Removed Cobblemon Vivillon patterns from advancement for time being, so this can be merged
2023-10-31 12:15:26 +10:00
dhi_holo a525df98cd Merge branch 'main' into blame-json 2023-10-31 12:14:19 +10:00
Licious 6a5c52ca0e Add the Fairy Feather. 2023-10-30 11:40:47 +00:00
Licious 57509b6bba Fix typo. 2023-10-30 11:21:27 +00:00
Licious 0a4b7fe5c8 Added the cleanse tag. 2023-10-30 11:21:19 +00:00
Hiroku 45f72e0e9e Merge branch 'spawner-fixes' into 'main'
Two spawner fixes

See merge request cable-mc/cobblemon!732
2023-10-30 07:30:06 +00:00
Deltric 029e152d95 Updated changelog for spawning fixes. 2023-10-30 02:00:22 -05:00
Deltric 08d6fa00eb Two spawner fixes 2023-10-30 01:47:36 -05:00
Hiroku 35bb803fb0 Merge branch 'battle-lang-fix' into 'main'
Battle lang fix

Closes #617 and #637

See merge request cable-mc/cobblemon!731
2023-10-29 23:48:38 +00:00
Plastered_Crab ec028c89e4 Update CHANGELOG.md 2023-10-29 18:47:27 +00:00
Plastered_Crab 1de8a40bae Added case for Disable to ShowdownInterpreter.kt 2023-10-29 18:45:24 +00:00
Plastered_Crab 8c682356bb Added extra battle text for various moves en_us.json 2023-10-29 18:42:33 +00:00
dhi_holo f7adaa6100 Moving recipes to correct root (4/4) 2023-10-29 01:16:51 +00:00
dhi_holo 7381ef6a02 Moving recipes to correct root (3/4) 2023-10-29 01:16:36 +00:00
dhi_holo a54acc48e7 Moving recipes to correct root (2/4) 2023-10-29 01:16:14 +00:00
dhi_holo 5478db4e32 Moving recipes to correct root (1/4) 2023-10-29 01:15:59 +00:00
Licious 5f55cbb5d3 Implement Apricorn boats & signs, pending texture approval. Fix a few missing item tags in CobblemonItemTags. Added support for injecting into specific points of ItemGroups. 2023-10-28 15:20:08 +01:00
tyzillion dfa104d8cf Updated Pokeball animations and model tweaks.
- Added cries to Raticate, Onix, Unfezant, Bergmite, Avalugg, Boltund, Revavroom.
- Turtwig can now be put on shoulder.
- Added animations for Hitmontop, Tyrogue, and Mightyena.
- Tweaked animations for Bewear, Exeggutor, and Alolan Exeggutor.
- Sized Kantonian Exeggutor down. Still big but not TOO BIG.
2023-10-26 15:07:39 -04:00
tyzillion 6ff53c0be3 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon 2023-10-26 15:04:49 -04:00
dhi_holo 088159bab2 Advancements Fixed
Repairs harvest_apricorn_seed and catch_all_vivillon advancements (can't be merged until confirmation on whether the Vivillon forms are ready for 1.4.1 or not)
2023-10-26 16:02:23 +10:00
tyzillion 6682049be1 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into implement_pokemon 2023-10-25 20:17:49 -04:00
tyzillion fa2bbdbb10 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2023-10-25 20:17:02 -04:00
Sterrezo 2798f73397 Fixed a couple missing cries
Fixed typo in farfetchd_galar.animation.json, added a cry provider to QuaxwellModel.kt, added a placeholder cry for Raticate, added missing sound keyframes to Onix, Unfezant, Bergmite, Avalugg, Boltund, Revavroom
2023-10-21 20:13:25 +02:00
1157 changed files with 33949 additions and 9503 deletions

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
<!-- 1. START HERE: (Before filling all this out, please quickly go to the list of all issues: (https://gitlab.com/cable-mc/cobblemon/-/issues/?sort=created_date&state=all) and do a quick search to see if your issue has already been reported. If it has, please add a comment to the existing issue instead of creating a new one.)-->
<!-- 2. If the issue was not already reported, please fill out the following template. -->
<!-- 3. If you do not know something, don't worry! Just fill out as much as you can to make sure the issue can get fixed asap. -->
## Summary
(Please summarize the bug encountered concisely)
## Steps to reproduce
(How one can reproduce the issue - this is very important)
## What is the current bug behavior?
(What actually happens)
## What is the expected correct behavior?
(What you should see instead)
## Cobblemon Version and Mod Loader
(Are you using Forge or Fabric? And what version of Cobblemon are you using?)
## Mods used besides Cobblemon
(Did you have any other mods installed besides Cobblemon? If so, please list them here)
## Relevant logs, screenshots and/or videos
(Paste any relevant logs - use code blocks (```) at the start and end to format console output, logs, and code, as
it's very hard to read otherwise. Or just put a link here)
## Additional Information
(If you can, link to the line of code that might be responsible for the problem, or any other info that might be useful)
/label ~bug
@@ -0,0 +1,31 @@
<!-- 1. START HERE: (Before filling all this out, please quickly go to the list of all issues: (https://gitlab.com/cable-mc/cobblemon/-/issues/?sort=created_date&state=all) and do a quick search to see if your feature was already requested. If it is, please add a comment to the existing issue instead of creating a new one.)-->
<!-- 2. If the feature request was not already reported, please fill out the following template. -->
<!-- 3. If you do not know something, don't worry! Just fill out as much as you can. -->
<!-- 4. The more info you provide here, the greater the chance of it being considered by the Design team. -->
## Summary
(Please summarize your feature request concisely)
## What are the projected benefits of this feature?
- (List)
- (benefits)
- (here)
## What could speak against this feature?
- (List)
- (possible)
- (cons)
## Why do you think the benefits outweigh the cons?
(Explain why you think the benefits outweigh the cons)
## Mods involved besides Cobblemon
(Does your suggestion require any other mods besides Cobblemon? If so, please list them here)
## Sketches, screenshots and/or videos
(Feel free to add any sketches, screenshots or videos that might help the Design team understand your suggestion)
## Additional Information
(Is there anything else you would like to add?)
/label ~feature ~suggestion ~needs-design
+117 -23
View File
@@ -1,38 +1,132 @@
# Changelog
## [1.4.1](#1-4-1)
### Changes
- Slightly lowered the volume of all cries
- Pasture blocks will now also connect their bottom left and right sides to walls, iron bars, glass panes and any other modded block that follows the same connection rules.
## [1.4.1 (December 23rd, 2023)](#1-4-1)
### Additions
- Cobblemon now has compatibility with [Adorn](https://modrinth.com/mod/adorn) allowing you to craft Apricorn wood furniture.
- Added battle spectating. Press R on a player in a battle and you can spectate and bully them for their tactics.
- Added the Litwick and Drifloon lines.
- Cobblemon now has compatibility with [Adorn](https://modrinth.com/mod/adorn), allowing you to craft Apricorn wood furniture.
- Berries can now be used in recipes from [Farmer's Delight](https://modrinth.com/mod/farmers-delight) and [Farmer's Delight (Fabric)](https://modrinth.com/mod/farmers-delight-fabric), as well as any other mods using the same berry tags.
- The nature of cobblemon will now be displayed italicized when a mint has been applied. Hovering over the nature will display the mint that was applied. This is the intended behaviour, because the original nature and taste of the Cobblemon does not change when a mint is applied.
- Boats, signs and hanging signs are now craftable with Apricorn wood.
- Added the Fairy Feather, Iron Ball, Cleanse Tag, Flame Orb, Life Orb, Smoke Ball, and Toxic Orb held items.
- Added the Inferno, Void, and Forsaken patterns for Vivillon. These can be obtained by evolving a Spewpa in the Nether, End, or Deep Dark respectively.
- Bees can now be fed using Pep-Up Flowers.
- Mooshtank can now be milked with a bowl for Mushroom Stew.
- Updated Showdown version to use generation 9 battle data.
- Added cries to Beldum, Metang and Metagross.
- Added a /bedrockparticle command to run Snowstorm-format particle effects.
- Added data for Dipplin, Fezandipiti, Munkidori, Ogerpon, Okidogi, Poltchageist and Sinistcha.
### Changes
- Using Potions, Status Heals, Ethers, and Antidotes will now return a glass bottle
- Using a Remedy, Fine Remedy, or Superb Remedy will no longer lower friendship with a Pokémon.
- The Healing Machine now has a [much more difficult recipe](https://wiki.cobblemon.com/index.php/Healing_Machine), placing it later game.
- Made the EXP. Share recipe cheaper.
- Turtwig can now be put on your shoulder.
- Updated Zubat line model, texture, and animations.
- Updated Geodude line models and textures.
- Added animations for Hitmontop, Tyrogue, and Mightyena.
- Tweaked animations for Dusknoir, Ratatta, Bewear, Exeggutor, and Alolan Exeggutor.
- Sized Kantonian Exeggutor down. Still big, but not TOO big.
- Tweaked cries for Pikachu, Raichu and Alolan Raichu.
- Fixed Swimming behaviors for Wimpod line, Oshawott line, Quaxly line, and Clodsire
- Changed the way level scaling works in spawning. By default, anything with a spawn range of up to 5 either side of the party highest level and everything else will spawn per its specified ranges.
- The nature of Pokémon will now be displayed italicized when a mint has been applied. Hovering over the nature will display the mint that was applied.
- Slightly lowered the volume of all cries.
- Giving Pokémon items now plays a sound
- Updated the Poké Ball model and animations.
- Pasture blocks will now also connect their bottom left and right sides to walls, iron bars, glass panes, and any other modded block that follows the same connection rules.
- The config option `consumeHeldItems` has been removed, please see the Datapack & Resourcepack Creators section for instructions on the updated method.
- Heal Powder can now be composted with a 75% chance of adding a layer
- Mental, Power, White, and Mirror Herbs can now be composted with a 100% chance of adding a layer.
- Added glowing eyes to Hoothoot and Noctowl.
- Mining Evolution Stone Ores with a Fortune pickaxe will now increase the amount of items received.
- Black Augurite can now be used to craft stone axes and obsidian.
- Using Experience Candies brings up the Party Pokémon Select screen when not targeting a Pokémon.
- Added tab completion for statuses to commands.
- Remedies can now be cooked in a Smoker and on a Campfire.
- Vertically flipped the Destiny Knot recipe.
### Fixes
- Fixed various stone related blocks not being valid for Big Roots to spread on the Fabric version.
- Fixed Raticate, Onix, Unfezant, Bergmite, Avalugg, Boltund and Revavroom cries not playing.
- Fixed Alolan Ratticate animations causing a crash.
- Fixed Quaxwell not doing its cry.
- Fixed Shroomish not using its idle.
- Fixed how Weight and Height is calculated for Pokémon, fixing the damage from moves like Low Kick.
- Fixed a staggering number of battle messages.
- Fixed various stone related blocks not being valid for Big Roots to spread onto on the Fabric version.
- Updated the registration of compostable items to improve compatibility with Fabric forks such as Quilt. Please note this does not mean we officially support Quilt, this change was only done since it was possible by correcting the registration to use the new intended way in the Fabric API.
- Fixed Dispensers being unable to shear grown Apricorns.
- Fixed Bowl not being given back to player after using Berry Juice
- Fixed missing text for attempting to catch an uncatchable Pokémon
- Fixed Moonphases for Clefairy line
- Fixed issue where Potions, Super Potions, and Hyper Potions did not work during battle
- Fixed the compatibility patch with the Forge version of [Carry On](https://modrinth.com/mod/carry-on) due to a bug on the mod, the Fabric version was unchanged and is still compatible.
- Added the ability to place Berries on modded Farmland blocks.
- Shouldered Pokémon now hop off when selected in team and r is pressed. This also is in effect in battles leading to shouldered Pokémon jumping of the shoulder of the trainer when it is their turn.
- Shouldered Pokémon now hop off when selected in team and R is pressed. This also is in effect in battles leading to shouldered Pokémon jumping of the shoulder of the trainer when it is their turn.
- Made more items compostable and changed the process for making items compostable.
- Added the ability for Hoppers to fill Brewing Stands with Medicinal Brews and Potions.
- Apricorn blocks are now flammable.
- Apricorn blocks are now flammable. Probably should have started that way, but we got there.
- The default pose for Pokémon being passengers is now "standing".
- Fixed issue where some IVs were changing every player relog.
- Fixed cursed battle message
- Fixed mistakes in pokemon spawning JSONs
- Fixed issue where some IVs were changing every time a player logged back in.
- Fixed advancement crash from bad datapack evolution data.
- Fixed global influences being applied to TickingSpawners twice.
- Reverted the default SpawningSelector back to FlatContextWeightedSelector. This fixes multiple weight related issues, including weights with SpawningInfluences.
- Apricorn Planting advancement should work again.
- Advancement "Vivillonaire" should now allow High Plains and Icy Snow Vivillon to register.
- Fixed the last battle critical hits evolution requirement not working.
- Fixed the damage taken evolution requirement not saving progress.
- Fixed the defeated Pokémon evolution requirement not saving progress.
- Fixed potion brewing recipes not showing up JEI and similar mods on the Forge version.
- Fixed an exploit that could convert a single piece of Blaze Powder into an extra Medicinal Brew on the Forge version.
- Fixed an issue where health percentages would show incorrectly after healing
- Fixed the move Revival Blessing not allowing you to select from fainted party members.
- Fixed villagers not being able to pick up and plant mint seeds, vivichoke seeds, and revival herbs.
- Fixed Exeggcute faint.
- Fixed various spawn configuration issues across the board.
- Fixed a possible visual duplication of sent out Pokémon.
- Fixed battle text for Trace, Receiver, and Power of Alchemy.
- Fixed tooltips being appended too late in items.
- Fixed battles ending background music when battle music is not present.
- Fixed battles ending background music, instead of pausing, when battle music is played.
- Fixed a bunch of regionals to actually be obtainable, namely the unmodelled ones
- Fixed battle text for moves that were missing.
- Fixed a formatting error that affected Pokémon nicknames when the storage type is JSON.
- Fixed a crash that could occur on some servers relating to chunk loading and teleporting.
- Fixed an issue with Inkay's evolution requirement.
- Fixed conflicting evolution requirements that would cause the Ocean, River, Sun, and Tundra variants of Vivillon to be unobtainable through evolution.
- Fixed the Modern variant of Vivillon not being obtainable through evolution.
- Fixed Pokémon pathing through berry bushes, harming themselves in the process.
### Developer
- Fixed the `SpawnEvent` not respecting usage of `Cancelable#cancel`.
- Added the `EvolutionTestedEvent`, this allows listening and overriding the final result of evolution requirement tests.
- Added utility script that can be used to generate all Spawn JSONS for all pokemon from the spawning spreadsheet in 1 click ([cobblemon_spawn_csv_to_json.py](utilityscripts%2Fcobblemon_spawn_csv_to_json.py)).
- The `HeldItemManager` has a new method `shouldConsumeItem`, this will return false by default to prevent breaking changes, see the documentation and update your implementations as needed.
- Added and implemented minSkyLight and maxSkyLight as config options for SpawnConditions
- Player specific battle themes can now be assigned to `PlayerData#battleTheme`.
- Changed design of `BattleStartedPreEvent`. Will now expose the `PokemonBattle`.
### Datapack & Resourcepack Creators
- Added 3 new item tags: `cobblemon:held/consumed_in_npc_battle`, `cobblemon:held/consumed_in_pvp_battle` & `cobblemon:held/consumed_in_wild_battle` these will determine which items get consumed in the implied battle types by Cobblemon, keep in mind the controller for this behaviour can be overriden by 3rd party.
- Unique wild encounter themes can now be associated with a specific species (or form) by assigning a SoundEvent identifier to the `battleTheme` field in the species' data configuration.
- Added a `structure` evolution condition, used to check if a Pokémon is in a given structure.
### Localization
- Updated translations for:
- French and Canadian French
- Simplified and Traditional Chinese
- Spanish and Mexican Spanish
- Pirate English
- German
- Thai
- Portuguese and Brazilian Portuguese
- Polish
- Italian
- Dutch
- Ukrainian
- Russian
Thank you so much to all of our community translators that bring the mod to the rest of the world!
## [1.4.0 - The Friends and Farms Update (October 13th, 2023)](#1-4-0)
### Additions
@@ -821,17 +915,17 @@
- Fixed spawning in several biome tag categories.
- Fixed resource pack support for Pokémon models and textures.
- **Model Fixes**
- Fixed Paras and Nidoqueen looking very weird.
- Fixed Hitmonchan asserting dominance with a T-pose as well as Grimer and Muk pointing their hands to the sky.
- Fixed specific Pokémon suddenly pausing their animation after staying still for a long time.
- Fixed Mankey's feet being buried in the ground.
- Updated the Substitute model and updated its shiny texture to be better for the red-green colorblind.
- Improved Horsea, Seadra, and Kingdra animations, especially on land.
- Fixed Paras and Nidoqueen looking very weird.
- Fixed Hitmonchan asserting dominance with a T-pose as well as Grimer and Muk pointing their hands to the sky.
- Fixed specific Pokémon suddenly pausing their animation after staying still for a long time.
- Fixed Mankey's feet being buried in the ground.
- Updated the Substitute model and updated its shiny texture to be better for the red-green colorblind.
- Improved Horsea, Seadra, and Kingdra animations, especially on land.
- **Battle Fixes**
- Fixed an issue with battles where Pokémon had a different max HP causing some desync issues with the health bars.
- Fixed Magnitude battle messages.
- Moves that are disabled or out of PP now show transparently in the battle GUI instead of being hidden completely.
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
- Fixed an issue with battles where Pokémon had a different max HP causing some desync issues with the health bars.
- Fixed Magnitude battle messages.
- Moves that are disabled or out of PP now show transparently in the battle GUI instead of being hidden completely.
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
### Localization
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
@@ -6,10 +6,15 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.access;
package com.cobblemon.mod.common.duck;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
public interface SoundManagerDuck {
void toggleCategories(SoundCategory... categories);
void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category);
void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category);
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.duck;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface SoundSystemDuck {
void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category);
void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category);
Collection<SoundInstance> getSounds(@Nullable SoundCategory category);
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.village.VillagerProfession;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.cobblemon.mod.common.villager.VillagerGatherableItems;
import java.util.Objects;
@Mixin(VillagerEntity.class)
public abstract class EntityVillagerMixin {
@Inject(method = "canGather", at = @At(value = "RETURN"), cancellable = true)
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
final VillagerEntity villager = (VillagerEntity) (Object) this;
if(ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canInsert(stack)) {
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
ci.setReturnValue(true);
}
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.sound.MusicTracker;
import net.minecraft.client.sound.SoundInstance;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(MusicTracker.class)
public class MusicTrackerMixin {
@Shadow @Final
private MinecraftClient client;
@Shadow @Nullable
private SoundInstance current;
/** Freezes the tracker while a BattleMusicInstance is in progress. Current SoundInstance being tracked will be paused by BattleMusicHandler. */
@Inject(method = "tick()V", at = @At("HEAD"), cancellable = true)
public void tick(CallbackInfo cb) {
if (this.client.getSoundManager().isPlaying(BattleMusicController.INSTANCE.getMusic())) cb.cancel();
}
}
@@ -8,36 +8,77 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.access.SoundManagerDuck;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.client.sound.SoundManager;
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
import com.cobblemon.mod.common.duck.SoundManagerDuck;
import com.cobblemon.mod.common.duck.SoundSystemDuck;
import net.minecraft.client.sound.*;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(SoundManager.class)
public class SoundManagerMixin implements SoundManagerDuck {
public abstract class SoundManagerMixin implements SoundManagerDuck {
private boolean[] blockedCategories = new boolean[SoundCategory.values().length];
@Shadow
public abstract boolean isPlaying(SoundInstance sound);
@Override
public void toggleCategories(SoundCategory... categories) {
for (SoundCategory category : categories) {
int index = category.ordinal();
boolean blocked = blockedCategories[index];
blockedCategories[index] = !blocked;
}
@Shadow @Final
private SoundSystem soundSystem;
// Never-ending ambient loops are a special exception (they are only initiated once) and should always be paused if filtered.
private boolean isAmbientLoop(SoundInstance sound) {
return sound instanceof BiomeEffectSoundPlayer.MusicLoop || sound instanceof AmbientSoundLoops.Underwater;
}
private boolean filterCondition(SoundInstance sound) {
return !isAmbientLoop(sound) &&
this.isPlaying(BattleMusicController.INSTANCE.getMusic()) &&
BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory());
}
private boolean ambientLoopCondition(SoundInstance sound) {
return isAmbientLoop(sound) &&
this.isPlaying(BattleMusicController.INSTANCE.getMusic()) &&
BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory());
}
/** Pauses the queried SoundInstance(s). If id is null, will pause all sounds belonging to the SoundCategory. */
@Override
public void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
((SoundSystemDuck)soundSystem).pauseSounds(id, category);
}
/** Resumes the queried SoundInstance(s). If id is null, will resume all sounds belonging to the SoundCategory. */
@Override
public void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
((SoundSystemDuck)soundSystem).resumeSounds(id, category);
}
/** Blocks filtered sounds from being played while a BattleMusicInstance is in progress. */
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("HEAD"), cancellable = true)
public void play(SoundInstance sound, CallbackInfo cb) {
if (blockedCategories[sound.getCategory().ordinal()]) cb.cancel();
public void playStart(SoundInstance sound, CallbackInfo cb) {
if (filterCondition(sound)) cb.cancel();
}
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;I)V", at = @At("HEAD"), cancellable = true)
public void play(SoundInstance sound, int delay, CallbackInfo cb) {
if (blockedCategories[sound.getCategory().ordinal()]) cb.cancel();
public void playStart(SoundInstance sound, int delay, CallbackInfo cb) {
if (filterCondition(sound)) cb.cancel();
}
/** Pauses ambient loops while a BattleMusicInstance is in progress. */
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("TAIL"))
public void playEnd(SoundInstance sound, CallbackInfo cb) {
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getId(), SoundCategory.AMBIENT);
}
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;I)V", at = @At("TAIL"))
public void playEnd(SoundInstance sound, int delay, CallbackInfo cb) {
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getId(), SoundCategory.AMBIENT);
}
}
@@ -8,31 +8,102 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
import com.cobblemon.mod.common.duck.SoundSystemDuck;
import com.google.common.collect.Multimap;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.client.sound.SoundSystem;
import net.minecraft.client.sound.*;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(SoundSystem.class)
public abstract class SoundSystemMixin {
public abstract class SoundSystemMixin implements SoundSystemDuck {
@Shadow
private boolean started;
@Shadow
private Multimap<SoundCategory, SoundInstance> sounds;
@Shadow @Final
private Map<SoundInstance, Channel.SourceManager> sources;
@Shadow
protected abstract void stop(SoundInstance sound);
@Shadow
public abstract boolean isPlaying(SoundInstance sound);
/** Resumes the Source belonging to the queried SoundInstance. */
private void resume(SoundInstance sound) {
Channel.SourceManager sourceManager = this.sources.get(sound);
if (this.started && sourceManager != null) sourceManager.run(Source::resume);
}
/** Pauses the Source belonging to the queried SoundInstance. */
private void pause(SoundInstance sound) {
Channel.SourceManager sourceManager = this.sources.get(sound);
if (this.started && sourceManager != null) sourceManager.run(Source::pause);
}
/** Resumes the SoundInstance(s) queried by id and/or category. */
@Override
public void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
if (category != null) {
this.sounds.get(category).forEach((sound) -> {
if (id == null || sound.getId().equals(id)) resume(sound);
});
} else if (id == null) {
this.sources.keySet().forEach(this::resume);
} else {
this.sources.keySet().forEach(sound -> {
if (sound.getId().equals(id)) resume(sound);
});
}
}
/** Pauses the SoundInstances queried by id and/or category. */
@Override
public void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
if (category != null) {
this.sounds.get(category).forEach((sound) -> {
if (id == null || sound.getId().equals(id)) pause(sound);
});
} else if (id == null) {
this.sources.keySet().forEach(this::pause);
} else {
this.sources.keySet().forEach(sound -> {
if (sound.getId().equals(id)) pause(sound);
});
}
}
/** Allows stopping all SoundInstances that belong to a queried category. */
@Inject(method = "stopSounds(Lnet/minecraft/util/Identifier;Lnet/minecraft/sound/SoundCategory;)V", at = @At("HEAD"), cancellable = true)
public void stopSounds(@Nullable Identifier id, @Nullable SoundCategory category, CallbackInfo cb) {
if (id == null && category != null) {
sounds.get(category).forEach(this::stop);
this.sounds.get(category).forEach(this::stop);
cb.cancel();
}
}
/** Different behavior for resuming SoundInstances while a BattleMusicInstance is being played. We do not want to resume filtered sounds. */
@Inject(method = "resumeAll()V", at = @At("HEAD"), cancellable = true)
public void resumeAll(CallbackInfo cb) {
if (this.isPlaying(BattleMusicController.INSTANCE.getMusic())) {
this.sounds.values().forEach(sound -> {
if (sound == BattleMusicController.INSTANCE.getMusic() || !BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory())) {
resume(sound);
}
});
cb.cancel();
}
}
@@ -8,15 +8,16 @@
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.sound.MusicTracker;
import net.minecraft.entity.vehicle.BoatEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(MusicTracker.class)
public interface MusicTrackerAccessor {
@Accessor("timeUntilNextSong")
int timeUntilNextSong();
@Mixin(BoatEntity.class)
public interface BoatEntityAccessor {
@Accessor("timeUntilNextSong")
void setTimeUntilNextSong(int timeUntilNextSong);
@Accessor
void setFallVelocity(double fallVelocity);
@Accessor
BoatEntity.Location getLocation();
}
@@ -371,8 +371,9 @@ object Cobblemon {
battleRegistry.startBattle(
BattleFormat.GEN_9_SINGLES,
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F))
).apply { mute = true }
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
true
).ifSuccessful { it.mute = true }
}
}
@@ -8,10 +8,7 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
import com.cobblemon.mod.common.block.entity.PCBlockEntity
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.block.entity.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.registry.Registries
@@ -31,5 +28,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
val BERRY = this.create("berry", BlockEntityType.Builder.create(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
@JvmField
val PASTURE: BlockEntityType<PokemonPastureBlockEntity> = this.create("pasture", BlockEntityType.Builder.create(::PokemonPastureBlockEntity, CobblemonBlocks.PASTURE).build(null))
@JvmField
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.create(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN).build(null))
@JvmField
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
}
@@ -19,6 +19,10 @@ import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
import net.minecraft.block.*
import net.minecraft.block.piston.PistonBehavior
import net.minecraft.entity.effect.StatusEffects
@@ -107,9 +111,14 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
val APRICORN_BUTTON = this.create("apricorn_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
@JvmField
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), APRICORN_BLOCK_SET_TYPE))
// Tag was removed be sure to add it back when implemented
//val APRICORN_SIGN = queue("apricorn_sign") { StandingSignBlock(AbstractBlock.Settings.of(Material.WOOD).noCollission().strength(1.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE) }
//val APRICORN_WALL_SIGN = queue("apricorn_wall_sign") { WallSignBlock(AbstractBlock.Settings.of(Material.WOOD).noCollission().strength(1.0f).sounds(BlockSoundGroup.WOOD).dropsLike(APRICORN_SIGN), APRICORN_WOOD_TYPE) }
@JvmField
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_WALL_SIGN = this.create("apricorn_wall_sign", CobblemonWallSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_WALL_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", CobblemonHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_WALL_HANGING_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_WALL_HANGING_SIGN = this.create("apricorn_wall_hanging_sign", CobblemonWallHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common
import java.util.function.Supplier
import net.minecraft.block.Block
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
@@ -19,11 +18,14 @@ import net.minecraft.client.particle.ParticleFactory
import net.minecraft.client.particle.SpriteProvider
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.model.EntityModelLayer
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType
import net.minecraft.item.Item
import net.minecraft.particle.ParticleEffect
import net.minecraft.particle.ParticleType
import net.minecraft.resource.SynchronousResourceReloader
import java.util.function.Supplier
interface CobblemonClientImplementation {
fun registerLayer(modelLayer: EntityModelLayer, supplier: Supplier<TexturedModelData>)
@@ -38,5 +40,7 @@ interface CobblemonClientImplementation {
fun registerBlockColors(provider: BlockColorProvider, vararg blocks: Block)
fun <T : BlockEntity> registerBlockEntityRenderer(type: BlockEntityType<T>, factory: BlockEntityRendererFactory<T>)
fun <T : BlockEntity> registerBlockEntityRenderer(type: BlockEntityType<out T>, factory: BlockEntityRendererFactory<T>)
fun <T : Entity> registerEntityRenderer(type: EntityType<out T>, factory: EntityRendererFactory<T>)
}
@@ -46,5 +46,6 @@ object CobblemonCommands {
ClearPartyCommand.register(dispatcher)
ClearPCCommand.register(dispatcher)
PokemonRestartCommand.register(dispatcher)
BedrockParticleCommand.register(dispatcher)
}
}
@@ -9,6 +9,8 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
@@ -45,6 +47,24 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
.build(EMPTY_POKEBALL_KEY.toString())
)
@JvmField
val BOAT_KEY = cobblemonResource("boat")
@JvmField
val BOAT: EntityType<CobblemonBoatEntity> = this.create(
BOAT_KEY.path,
EntityType.Builder.create(::CobblemonBoatEntity, SpawnGroup.MISC).setDimensions(1.375F, 0.5625F).maxTrackingRange(10)
.build(BOAT_KEY.toString())
)
@JvmField
val CHEST_BOAT_KEY = cobblemonResource("chest_boat")
@JvmField
val CHEST_BOAT: EntityType<CobblemonChestBoatEntity> = this.create(
CHEST_BOAT_KEY.path,
EntityType.Builder.create(::CobblemonChestBoatEntity, SpawnGroup.MISC).setDimensions(1.375F, 0.5625F).maxTrackingRange(10)
.build(CHEST_BOAT_KEY.toString())
)
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
consumer(POKEMON, PokemonEntity.createAttributes())
}
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.MintBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.*
import com.cobblemon.mod.common.item.battle.DireHitItem
import com.cobblemon.mod.common.item.battle.GuardSpecItem
@@ -27,7 +28,6 @@ import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
@@ -36,7 +36,13 @@ import net.minecraft.block.Block
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.effect.StatusEffectInstance
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.item.*
import net.minecraft.item.BlockItem
import net.minecraft.item.FoodComponent
import net.minecraft.item.HangingSignItem
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.SignItem
import net.minecraft.item.StewItem
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
@@ -123,34 +129,34 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val VIVICHOKE_SEEDS = compostableItem("vivichoke_seeds", VivichokeItem(CobblemonBlocks.VIVICHOKE_SEEDS))
@JvmField
val RED_APRICORN = apricronItem("red", ApricornItem(CobblemonBlocks.RED_APRICORN))
val RED_APRICORN = apricornItem("red", ApricornItem(CobblemonBlocks.RED_APRICORN))
@JvmField
val YELLOW_APRICORN = apricronItem("yellow", ApricornItem(CobblemonBlocks.YELLOW_APRICORN))
val YELLOW_APRICORN = apricornItem("yellow", ApricornItem(CobblemonBlocks.YELLOW_APRICORN))
@JvmField
val GREEN_APRICORN = apricronItem("green", ApricornItem(CobblemonBlocks.GREEN_APRICORN))
val GREEN_APRICORN = apricornItem("green", ApricornItem(CobblemonBlocks.GREEN_APRICORN))
@JvmField
val BLUE_APRICORN = apricronItem("blue", ApricornItem(CobblemonBlocks.BLUE_APRICORN))
val BLUE_APRICORN = apricornItem("blue", ApricornItem(CobblemonBlocks.BLUE_APRICORN))
@JvmField
val PINK_APRICORN = apricronItem("pink", ApricornItem(CobblemonBlocks.PINK_APRICORN))
val PINK_APRICORN = apricornItem("pink", ApricornItem(CobblemonBlocks.PINK_APRICORN))
@JvmField
val BLACK_APRICORN = apricronItem("black", ApricornItem(CobblemonBlocks.BLACK_APRICORN))
val BLACK_APRICORN = apricornItem("black", ApricornItem(CobblemonBlocks.BLACK_APRICORN))
@JvmField
val WHITE_APRICORN = apricronItem("white", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
val WHITE_APRICORN = apricornItem("white", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
@JvmField
val RED_APRICORN_SEED = apricronSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING))
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING))
@JvmField
val YELLOW_APRICORN_SEED = apricronSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING))
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING))
@JvmField
val GREEN_APRICORN_SEED = apricronSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING))
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING))
@JvmField
val BLUE_APRICORN_SEED = apricronSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING))
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING))
@JvmField
val PINK_APRICORN_SEED = apricronSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING))
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING))
@JvmField
val BLACK_APRICORN_SEED = apricronSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING))
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING))
@JvmField
val WHITE_APRICORN_SEED = apricronSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING))
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING))
@JvmField
val APRICORN_LOG = blockItem("apricorn_log", CobblemonBlocks.APRICORN_LOG)
@@ -164,6 +170,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val APRICORN_PLANKS = blockItem("apricorn_planks", CobblemonBlocks.APRICORN_PLANKS)
@JvmField
val APRICORN_LEAVES = compostableBlockItem("apricorn_leaves", CobblemonBlocks.APRICORN_LEAVES)
@JvmField
val APRICORN_BOAT = create("apricorn_boat", CobblemonBoatItem(CobblemonBoatType.APRICORN, false, Item.Settings().maxCount(1)))
@JvmField
val APRICORN_CHEST_BOAT = create("apricorn_chest_boat", CobblemonBoatItem(CobblemonBoatType.APRICORN, true, Item.Settings().maxCount(1)))
@JvmField
val APRICORN_DOOR = blockItem("apricorn_door", CobblemonBlocks.APRICORN_DOOR)
@@ -177,12 +187,14 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val APRICORN_BUTTON = blockItem("apricorn_button", CobblemonBlocks.APRICORN_BUTTON)
@JvmField
val APRICORN_PRESSURE_PLATE = blockItem("apricorn_pressure_plate", CobblemonBlocks.APRICORN_PRESSURE_PLATE)
//@JvmField
// val APRICORN_SIGN = create("apricorn_sign", SignItem(Item.Properties().stacksTo(16).tab(CreativeModeTab.TAB_DECORATIONS), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
@JvmField
val APRICORN_SLAB = blockItem("apricorn_slab", CobblemonBlocks.APRICORN_SLAB)
@JvmField
val APRICORN_STAIRS = blockItem("apricorn_stairs", CobblemonBlocks.APRICORN_STAIRS)
@JvmField
val APRICORN_SIGN = this.create("apricorn_sign", SignItem(Item.Settings().maxCount(16), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
@JvmField
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
@JvmField
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE)
@@ -564,10 +576,14 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val CHOICE_SPECS = heldItem("choice_specs")
@JvmField
val CLEANSE_TAG = heldItem("cleanse_tag")
@JvmField
val DRAGON_FANG = heldItem("dragon_fang")
@JvmField
val EXP_SHARE = heldItem("exp_share")
@JvmField
val FAIRY_FEATHER = heldItem("fairy_feather")
@JvmField
val FOCUS_BAND = heldItem("focus_band")
@JvmField
val HARD_STONE = heldItem("hard_stone")
@@ -612,13 +628,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val WISE_GLASSES = heldItem("wise_glasses")
@JvmField
val MENTAL_HERB = compostableHeldItem("mental_herb")
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
@JvmField
val MIRROR_HERB = compostableHeldItem("mirror_herb")
val MIRROR_HERB = compostableHeldItem("mirror_herb", null, 1F)
@JvmField
val POWER_HERB = compostableHeldItem("power_herb")
val POWER_HERB = compostableHeldItem("power_herb", null, 1F)
@JvmField
val WHITE_HERB = heldItem("white_herb")
val WHITE_HERB = compostableHeldItem("white_herb", null, 1F)
@JvmField
val BRIGHT_POWDER = heldItem("bright_powder")
@JvmField
@@ -641,6 +657,14 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val POWER_LENS = heldItem("power_lens")
@JvmField
val POWER_WEIGHT = heldItem("power_weight")
@JvmField
val FLAME_ORB = heldItem("flame_orb")
@JvmField
val LIFE_ORB = heldItem("life_orb")
@JvmField
val TOXIC_ORB = heldItem("toxic_orb")
@JvmField
val SMOKE_BALL = heldItem("smoke_ball")
// Mulch
@JvmField
@@ -717,16 +741,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
return item
}
private fun apricronItem(name: String, apricornItem: ApricornItem): ApricornItem {
private fun apricornItem(name: String, apricornItem: ApricornItem): ApricornItem {
val finalName = "${name}_apricorn"
val item = this.create(finalName, apricornItem)
compostable(item, .65f)
return item
}
private fun apricronSeedItem(name: String, apricronSeedItem: ApricornSeedItem): ApricornSeedItem {
private fun apricornSeedItem(name: String, apricornSeedItem: ApricornSeedItem): ApricornSeedItem {
val finalName = "${name}_apricorn_seed"
val item = this.create(finalName, apricronSeedItem)
val item = this.create(finalName, apricornSeedItem)
compostable(item, .65f)
return item
}
@@ -11,8 +11,27 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
import com.cobblemon.mod.common.client.net.battle.*
import com.cobblemon.mod.common.client.net.battle.BattleApplyPassResponseHandler
import com.cobblemon.mod.common.client.net.battle.BattleCaptureEndHandler
import com.cobblemon.mod.common.client.net.battle.BattleCaptureShakeHandler
import com.cobblemon.mod.common.client.net.battle.BattleCaptureStartHandler
import com.cobblemon.mod.common.client.net.battle.BattleChallengeExpiredHandler
import com.cobblemon.mod.common.client.net.battle.BattleChallengeNotificationHandler
import com.cobblemon.mod.common.client.net.battle.BattleEndHandler
import com.cobblemon.mod.common.client.net.battle.BattleFaintHandler
import com.cobblemon.mod.common.client.net.battle.BattleHealthChangeHandler
import com.cobblemon.mod.common.client.net.battle.BattleInitializeHandler
import com.cobblemon.mod.common.client.net.battle.BattleMadeInvalidChoiceHandler
import com.cobblemon.mod.common.client.net.battle.BattleMakeChoiceHandler
import com.cobblemon.mod.common.client.net.battle.BattleMessageHandler
import com.cobblemon.mod.common.client.net.battle.BattleMusicHandler
import com.cobblemon.mod.common.client.net.battle.BattlePersistentStatusHandler
import com.cobblemon.mod.common.client.net.battle.BattleQueueRequestHandler
import com.cobblemon.mod.common.client.net.battle.BattleSetTeamPokemonHandler
import com.cobblemon.mod.common.client.net.battle.BattleSwitchPokemonHandler
import com.cobblemon.mod.common.client.net.battle.BattleUpdateTeamPokemonHandler
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
@@ -51,6 +70,7 @@ import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.client.battle.*
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
@@ -99,12 +119,10 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
@@ -134,7 +152,10 @@ import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptanceP
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSelectedHandler
@@ -168,12 +189,12 @@ import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHa
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.util.server
import kotlin.reflect.KClass
import net.minecraft.network.PacketByteBuf
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import kotlin.reflect.KClass
/**
* Registers Cobblemon network packets.
@@ -238,6 +259,7 @@ object CobblemonNetwork : NetworkManager {
// UI Packets
this.createClientBound(SummaryUIPacket.ID, SummaryUIPacket::decode, SummaryUIPacketHandler)
this.createClientBound(InteractPokemonUIPacket.ID, InteractPokemonUIPacket::decode, InteractPokemonUIPacketHandler)
this.createClientBound(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler)
// Starter packets
this.createClientBound(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler)
@@ -323,6 +345,7 @@ object CobblemonNetwork : NetworkManager {
// Interaction Packets
this.createServerBound(InteractPokemonPacket.ID, InteractPokemonPacket::decode, InteractPokemonHandler)
this.createServerBound(RequestPlayerInteractionsPacket.ID, RequestPlayerInteractionsPacket::decode, RequestInteractionsHandler)
// Storage Packets
this.createServerBound(SendOutPokemonPacket.ID, SendOutPokemonPacket::decode, SendOutPokemonHandler)
@@ -350,6 +373,8 @@ object CobblemonNetwork : NetworkManager {
// Battle packets
this.createServerBound(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler)
this.createServerBound(SpectateBattlePacket.ID, SpectateBattlePacket::decode, SpectateBattleHandler)
this.createServerBound(RemoveSpectatorPacket.ID, RemoveSpectatorPacket::decode, RemoveSpectatorHandler)
// Trade
this.createServerBound(AcceptTradeRequestPacket.ID, AcceptTradeRequestPacket::decode, AcceptTradeRequestHandler)
@@ -40,14 +40,15 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getPlayer
import java.io.File
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
import java.util.concurrent.ConcurrentLinkedDeque
/**
* Individual battle instance
@@ -55,6 +56,7 @@ import net.minecraft.text.Text
* @since January 16th, 2022
* @author Deltric, Hiroku
*/
@Suppress("unused", "MemberVisibilityCanBePrivate")
open class PokemonBattle(
val format: BattleFormat,
val side1: BattleSide,
@@ -67,8 +69,11 @@ open class PokemonBattle(
side1.battle = this
side2.battle = this
this.actors.forEach { actor ->
actor.battle = this
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.criticalHits = 0
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
.forEach { it.reset() }
}
}
}
@@ -82,12 +87,13 @@ open class PokemonBattle(
val playerUUIDs: Iterable<UUID>
get() = actors.flatMap { it.getPlayerUUIDs() }
val players = playerUUIDs.mapNotNull { it.getPlayer() }
val spectators = mutableListOf<UUID>()
val spectators = mutableSetOf<UUID>()
val battleId = UUID.randomUUID()
val showdownMessages = mutableListOf<String>()
val battleLog = mutableListOf<String>()
val chatLog = mutableListOf<Text>()
var started = false
var ended = false
// TEMP battle showcase stuff
@@ -97,7 +103,7 @@ open class PokemonBattle(
var dispatchResult = GO
val dispatches = ConcurrentLinkedQueue<BattleDispatch>()
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
val afterDispatches = mutableListOf<() -> Unit>()
val captureActions = mutableListOf<BattleCaptureAction>()
@@ -175,11 +181,8 @@ open class PokemonBattle(
}
fun broadcastChatMessage(component: Text) {
spectators.forEach { spectatorId ->
spectatorId.getPlayer()?.let {
CobblemonNetwork.sendPacketToPlayer(it, BattleMessagePacket(component))
}
}
chatLog.add(component)
sendSpectatorUpdate(BattleMessagePacket(component))
return actors.forEach { it.sendMessage(component) }
}
@@ -250,7 +253,6 @@ open class PokemonBattle(
}
}
sendUpdate(BattleEndPacket())
sendUpdate(BattleMusicPacket(null))
BattleRegistry.closeBattle(this)
}
@@ -317,6 +319,12 @@ open class PokemonBattle(
fun dispatch(dispatcher: () -> DispatchResult) {
dispatches.add(BattleDispatch { dispatcher() })
}
fun dispatchToFront(dispatcher: () -> DispatchResult) {
dispatches.addFirst(BattleDispatch { dispatcher() })
}
fun dispatchGo(dispatcher: () -> Unit) {
@@ -348,6 +356,10 @@ open class PokemonBattle(
dispatches.add(dispatcher)
}
fun dispatchToFront(dispatcher: BattleDispatch) {
dispatches.addFirst(dispatcher)
}
fun doWhenClear(action: () -> Unit) {
afterDispatches.add(action)
}
@@ -9,26 +9,19 @@
package com.cobblemon.mod.common.api.events.battles
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.battles.BattleFormat
import net.minecraft.text.MutableText
/**
* Event fired before a [PokemonBattle] is started. Canceling this event prevents the battle from being
* created and launched.
*
* @property reason The text used to inform the participants why the battle was canceled. Keep null for a default error.
*
* @author Segfault Guy
* @since March 26th 2023
*/
data class BattleStartedPreEvent (
val participants: Collection<BattleActor>,
val format: BattleFormat,
val isPvP: Boolean,
val isPvN: Boolean,
val isPvW: Boolean
) : Cancelable()
data class BattleStartedPreEvent (override val battle: PokemonBattle, var reason: MutableText? = null) : BattleEvent, Cancelable()
/**
* Event fired after a [PokemonBattle] starts.
@@ -36,8 +29,4 @@ data class BattleStartedPreEvent (
* @author Segfault Guy
* @since March 26th 2023
*/
data class BattleStartedPostEvent (
override val battle: PokemonBattle
) : BattleEvent
data class BattleStartedPostEvent (override val battle: PokemonBattle) : BattleEvent
@@ -196,6 +196,8 @@ fun drawPortraitPokemon(
val context = RenderContext()
PokemonModelRepository.getTextureNoSubstitute(species.resourceIdentifier, aspects, 0f).let { it -> context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, species.getForm(aspects).baseScale)
context.put(RenderContext.SPECIES, species.resourceIdentifier)
context.put(RenderContext.ASPECTS, aspects)
val renderType = model.getLayer(texture)
@@ -66,7 +66,15 @@ interface PokemonSelectingItem {
return if (entity != null) {
val pokemon = entity.pokemon
if (entity.ownerUuid == player.uuid) {
applyToPokemon(player, stack, pokemon) ?: TypedActionResult.pass(stack)
val typedActionResult = applyToPokemon(player, stack, pokemon)
if (typedActionResult != null)
{
CobblemonCriteria.POKEMON_INTERACT.trigger(player, PokemonInteractContext(pokemon.species.resourceIdentifier, Registries.ITEM.getId(stack.item)))
typedActionResult
}
else {
TypedActionResult.pass(stack)
}
} else {
TypedActionResult.fail(stack)
}
@@ -27,11 +27,13 @@ object CobblemonPermissions {
val HEAL_POKEMON_SELF = this.create("$HEAL_POKEMON_BASE.self", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
val HEAL_POKEMON_OTHER = this.create("$HEAL_POKEMON_BASE.other", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
private const val LEVEL_UP_BASE = "${COMMAND_PREFIX}levelup"
val LEVEL_UP_SELF = this.create("$LEVEL_UP_BASE.self", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
val LEVEL_UP_OTHER = this.create("$LEVEL_UP_BASE.other", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
val OPEN_STARTER_SCREEN = this.create("${COMMAND_PREFIX}openstarterscreen", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
val BEDROCK_PARTICLE = this.create("${COMMAND_PREFIX}bedrockparticle", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
private const val POKEMON_EDIT_BASE = "${COMMAND_PREFIX}pokemonedit"
val POKEMON_EDIT_SELF = this.create("$POKEMON_EDIT_BASE.self", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@@ -61,6 +61,7 @@ import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.math.Box
import net.minecraft.world.biome.Biome
import net.minecraft.world.gen.structure.Structure
object PokemonSpecies : JsonDataRegistry<Species> {
@@ -93,6 +94,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Structure::class.java).type, StructureLikeConditionAdapter)
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
.registerTypeAdapter(StatusEffect::class.java, RegistryElementAdapter<StatusEffect> { Registries.STATUS_EFFECT })
.registerTypeAdapter(NbtItemPredicate::class.java, NbtItemPredicateAdapter)
@@ -236,8 +238,8 @@ object PokemonSpecies : JsonDataRegistry<Species> {
"spd" to (form?.baseStats?.get(Stats.SPECIAL_DEFENCE) ?: species.baseStats[Stats.SPECIAL_DEFENCE] ?: 1),
"spe" to (form?.baseStats?.get(Stats.SPEED) ?: species.baseStats[Stats.SPEED] ?: 1)
)
val heightm = form?.height ?: species.height
val weightkg = form?.weight ?: species.weight
val heightm = (form?.height ?: species.height) / 10
val weightkg = (form?.weight ?: species.weight) / 10
// This is ugly, but we already have it hardcoded in the mod anyway
val maxHP = if (species.showdownId() == "shedinja") 1 else null
val canGigantamax: String? = if (form?.gigantamaxMove != null) form.gigantamaxMove.name else null
@@ -8,14 +8,16 @@
package com.cobblemon.mod.common.api.pokemon.evolution.progress
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.*
object EvolutionProgressFactory {
private val variants = hashMapOf<String, () -> EvolutionProgress<*>>()
init {
registerVariant(DamageTakenEvolutionProgress.ID.toString()) { DamageTakenEvolutionProgress() }
registerVariant(DefeatEvolutionProgress.ID.toString()) { DefeatEvolutionProgress() }
registerVariant(LastBattleCriticalHitsEvolutionProgress.ID.toString()) { LastBattleCriticalHitsEvolutionProgress() }
registerVariant(RecoilEvolutionProgress.ID.toString()) { RecoilEvolutionProgress() }
registerVariant(UseMoveEvolutionProgress.ID.toString()) { UseMoveEvolutionProgress() }
}
@@ -79,6 +79,16 @@ interface HeldItemManager {
*/
fun take(pokemon: BattlePokemon, showdownId: String)
/**
* Tests if the given [BattlePokemon] should have their item consumed.
* This method is expected to be used in each implementation when needed.
*
* @param pokemon The [BattlePokemon] being tested.
* @param battle The [PokemonBattle] the [pokemon] is participating in.
* @param showdownId The literal ID of the held item on Showdown.
*/
fun shouldConsumeItem(pokemon: BattlePokemon, battle: PokemonBattle, showdownId: String): Boolean = false
companion object {
/**
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.pokemon.status
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
@@ -39,4 +40,5 @@ object Statuses {
fun getStatus(name: Identifier) = allStatuses.find { status -> status.name == name }
fun getStatus(showdownName: String) = allStatuses.find { it.showdownName == showdownName }
fun getPersistentStatuses() = allStatuses.filterIsInstance<PersistentStatus>()
}
@@ -20,6 +20,7 @@ import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Box
import net.minecraft.util.math.ChunkSectionPos.getSectionCoord
import net.minecraft.util.math.Vec3d
import net.minecraft.world.LightType
import net.minecraft.world.chunk.Chunk
import net.minecraft.world.chunk.ChunkStatus
@@ -69,7 +70,7 @@ object CobblemonSpawningProspector : SpawningProspector {
.map { it.pos }
val defaultState = Blocks.STONE.defaultState
val defaultBlockData = WorldSlice.BlockData(defaultState, 0)
val defaultBlockData = WorldSlice.BlockData(defaultState, 0, 0)
val blocks = Array(area.length) { Array(height) { Array(area.width) { defaultBlockData } } }
val skyLevel = Array(area.length) { Array(area.width) { world.topY } }
@@ -77,6 +78,7 @@ object CobblemonSpawningProspector : SpawningProspector {
val chunks = mutableMapOf<Pair<Int, Int>, Chunk?>()
val yRange = (baseY until baseY + height).reversed()
val lightingProvider = world.lightingProvider
for (x in area.baseX until area.baseX + area.length) {
for (z in area.baseZ until area.baseZ + area.width) {
val query = chunks.computeIfAbsent(Pair(getSectionCoord(x), getSectionCoord(z))) {
@@ -85,16 +87,16 @@ object CobblemonSpawningProspector : SpawningProspector {
var canSeeSky = world.isSkyVisibleAllowingSea(pos.set(x, yRange.first, z))
for (y in yRange) {
val skyLight = lightingProvider.get(LightType.SKY).getLightLevel(pos.set(x, y, z))
val state = query.getBlockState(pos.set(x, y, z))
blocks[x - area.baseX][y - baseY][z - area.baseZ] = WorldSlice.BlockData(
state = state,
light = world.getLightLevel(pos)
light = world.getLightLevel(pos),
skyLight = skyLight
)
if (canSeeSky) {
skyLevel[x - area.baseX][z - area.baseZ] = y
}
if (state.fluidState.isEmpty && !state.isIn(CobblemonBlockTags.SEES_SKY)) {
canSeeSky = false
}
@@ -31,12 +31,16 @@ open class SpawnerManager {
open fun registerSpawner(spawner: Spawner) {
spawners.add(spawner)
spawner.influences.addAll(influences)
if (spawner !is TickingSpawner) {
spawner.influences.addAll(influences)
}
}
open fun unregisterSpawner(spawner: Spawner) {
spawners.remove(spawner)
spawner.influences.removeAll(influences)
if (spawner !is TickingSpawner) {
spawner.influences.removeAll(influences)
}
}
open fun onServerStarted() {
@@ -44,7 +44,8 @@ class WorldSlice(
) {
class BlockData(
val state: BlockState,
val light: Int
val light: Int,
val skyLight: Int
)
val length = blocks.size
@@ -83,6 +84,15 @@ class WorldSlice(
}
fun getLight(position: BlockPos, elseLight: Int = 0) = getLight(position.x, position.y, position.z, elseLight)
fun getSkyLight(x: Int, y: Int, z: Int, elseLight: Int = 0): Int {
return if (!isInBounds(x, y, z)) {
elseLight
} else {
getBlockData(x, y, z).skyLight
}
}
fun getSkyLight(position: BlockPos, elseLight: Int = 0) = getSkyLight(position.x, position.y, position.z, elseLight)
fun skySpaceAbove(x: Int, y: Int, z: Int): Int {
return if (!isInBounds(x, y, z) || skyLevel[x - baseX][z - baseZ] > y) {
0
@@ -52,6 +52,8 @@ abstract class SpawningCondition<T : SpawningContext> {
var maxZ: Float? = null
var minLight: Int? = null
var maxLight: Int? = null
var minSkyLight: Int? = null
var maxSkyLight: Int? = null
var isRaining: Boolean? = null
var isThundering: Boolean? = null
var timeRange: TimeRange? = null
@@ -88,6 +90,8 @@ abstract class SpawningCondition<T : SpawningContext> {
return false
} else if (ctx.light > maxLight.orMax() || ctx.light < minLight.orMin()) {
return false
} else if (ctx.skyLight > maxSkyLight.orMax() || ctx.skyLight < minSkyLight.orMin()) {
return false
} else if (timeRange != null && !timeRange!!.contains((ctx.world.timeOfDay % 24000).toInt())) {
return false
} else if (canSeeSky != null && canSeeSky != ctx.canSeeSky) {
@@ -134,6 +138,8 @@ abstract class SpawningCondition<T : SpawningContext> {
maxZ = merger.mergeSingle(maxZ, other.maxZ)
minLight = merger.mergeSingle(minLight, other.minLight)
maxLight = merger.mergeSingle(maxLight, other.maxLight)
minSkyLight = merger.mergeSingle(minSkyLight, other.minSkyLight)
maxSkyLight = merger.mergeSingle(maxSkyLight, other.maxSkyLight)
timeRange = merger.mergeSingle(timeRange, other.timeRange)
structures = merger.merge(structures, other.structures)?.toMutableList()
}
@@ -30,6 +30,7 @@ open class AreaSpawningContext(
override val world: ServerWorld,
override val position: BlockPos,
override val light: Int,
override val skyLight: Int,
override val canSeeSky: Boolean,
override val influences: MutableList<SpawningInfluence>,
/** Space above. */
@@ -27,12 +27,13 @@ abstract class FlooredSpawningContext(
world: ServerWorld,
position: BlockPos,
light: Int,
skyLight: Int,
canSeeSky: Boolean,
influences: MutableList<SpawningInfluence>,
height: Int,
nearbyBlocks: List<BlockState>,
slice: WorldSlice
) : AreaSpawningContext(cause, world, position, light, canSeeSky, influences, height, nearbyBlocks, slice) {
) : AreaSpawningContext(cause, world, position, light, skyLight, canSeeSky, influences, height, nearbyBlocks, slice) {
/** The block that the spawning is occurring on. */
val baseBlock = slice.getBlockState(position.x, position.y, position.z)
}
@@ -48,12 +49,13 @@ open class GroundedSpawningContext(
world: ServerWorld,
position: BlockPos,
light: Int,
skyLight: Int,
canSeeSky: Boolean,
influences: MutableList<SpawningInfluence>,
height: Int,
nearbyBlocks: List<BlockState>,
slice: WorldSlice
) : FlooredSpawningContext(cause, world, position, light, canSeeSky, influences, height, nearbyBlocks, slice)
) : FlooredSpawningContext(cause, world, position, light, skyLight, canSeeSky, influences, height, nearbyBlocks, slice)
/**
* A spawning context that occurs at the bottom of a body of water.
@@ -66,12 +68,13 @@ open class SeafloorSpawningContext(
world: ServerWorld,
position: BlockPos,
light: Int,
skyLight: Int,
canSeeSky: Boolean,
influences: MutableList<SpawningInfluence>,
height: Int,
nearbyBlocks: List<BlockState>,
slice: WorldSlice
) : FlooredSpawningContext(cause, world, position, light, canSeeSky, influences, height, nearbyBlocks, slice) {
) : FlooredSpawningContext(cause, world, position, light, skyLight, canSeeSky, influences, height, nearbyBlocks, slice) {
override fun isSafeSpace(world: ServerWorld, pos: BlockPos, state: BlockState) = state.fluidState.isIn(FluidTags.WATER)
}
@@ -86,12 +89,13 @@ open class LavafloorSpawningContext(
world: ServerWorld,
position: BlockPos,
light: Int,
skyLight: Int,
canSeeSky: Boolean,
influences: MutableList<SpawningInfluence>,
height: Int,
nearbyBlocks: List<BlockState>,
slice: WorldSlice
) : FlooredSpawningContext(cause, world, position, light, canSeeSky, influences, height, nearbyBlocks, slice) {
) : FlooredSpawningContext(cause, world, position, light, skyLight, canSeeSky, influences, height, nearbyBlocks, slice) {
override fun isSafeSpace(world: ServerWorld, pos: BlockPos, state: BlockState) = state.fluidState.isIn(FluidTags.LAVA)
}
@@ -100,10 +104,11 @@ open class SurfaceSpawningContext(
world: ServerWorld,
position: BlockPos,
light: Int,
skyLight: Int,
canSeeSky: Boolean,
influences: MutableList<SpawningInfluence>,
height: Int,
val depth: Int,
nearbyBlocks: List<BlockState>,
slice: WorldSlice
) : FlooredSpawningContext(cause, world, position, light, canSeeSky, influences, height, nearbyBlocks, slice)
) : FlooredSpawningContext(cause, world, position, light, skyLight, canSeeSky, influences, height, nearbyBlocks, slice)
@@ -61,6 +61,8 @@ abstract class SpawningContext {
abstract val position: BlockPos
/** The light level at this location. */
abstract val light: Int
/** The sky light level at this location. (15 - The distance to the nearest block that would be illuminated by the sun */
abstract val skyLight: Int
/** Whether or not the sky is visible at this location. */
abstract val canSeeSky: Boolean
/** A list of [SpawningInfluence]s that apply due to this specific context. */
@@ -26,13 +26,14 @@ open class SubmergedSpawningContext(
world: ServerWorld,
position: BlockPos,
light: Int,
skyLight: Int,
canSeeSky: Boolean,
influences: MutableList<SpawningInfluence>,
height: Int,
val depth: Int,
nearbyBlocks: List<BlockState>,
slice: WorldSlice
) : AreaSpawningContext(cause, world, position, light, canSeeSky, influences, height, nearbyBlocks, slice) {
) : AreaSpawningContext(cause, world, position, light, skyLight, canSeeSky, influences, height, nearbyBlocks, slice) {
val fluid = slice.getBlockState(position.x, position.y, position.z).fluidState
override fun isSafeSpace(world: ServerWorld, pos: BlockPos, state: BlockState) = state.fluidState.fluid == fluid.fluid
@@ -45,6 +45,8 @@ interface AreaSpawningContextCalculator<O : AreaSpawningContext> : SpawningConte
= input.slice.horizontalSpace(input.position.x + offsetX, input.position.y + offsetY, input.position.z + offsetZ, condition, maximum)
fun getLight(input: AreaSpawningInput, elseLight: Int = 0): Int
= input.slice.getLight(input.position.x, input.position.y + 1, input.position.z, elseLight)
fun getSkyLight(input: AreaSpawningInput, elseLight: Int = 0): Int
= input.slice.getSkyLight(input.position.x, input.position.y + 1, input.position.z, elseLight)
fun getCanSeeSky(input: AreaSpawningInput): Boolean = input.slice.canSeeSky(input.position.x, input.position.y + 1, input.position.z)
fun getSkySpaceAbove(input: AreaSpawningInput): Int = input.slice.skySpaceAbove(input.position.x, input.position.y, input.position.z)
fun getNearbyBlocks(
@@ -59,6 +59,7 @@ object GroundedSpawningContextCalculator : FlooredSpawningContextCalculator<Grou
world = input.world,
position = input.position.toImmutable(),
light = getLight(input),
skyLight = getSkyLight(input),
canSeeSky = getCanSeeSky(input),
influences = input.spawner.copyInfluences(),
height = getHeight(input, surroundingCondition, config.maxVerticalSpace, offsetY = 1),
@@ -85,6 +86,7 @@ object SeafloorSpawningContextCalculator : FlooredSpawningContextCalculator<Seaf
world = input.world,
position = input.position.toImmutable(),
light = getLight(input),
skyLight = getSkyLight(input),
canSeeSky = getCanSeeSky(input),
influences = input.spawner.copyInfluences(),
height = getHeight(input, surroundingCondition, config.maxVerticalSpace, offsetY = 1),
@@ -111,6 +113,7 @@ object LavafloorSpawningContextCalculator : FlooredSpawningContextCalculator<Lav
world = input.world,
position = input.position.toImmutable(),
light = getLight(input),
skyLight = getSkyLight(input),
canSeeSky = getCanSeeSky(input),
influences = input.spawner.copyInfluences(),
height = getHeight(input, surroundingCondition, config.maxVerticalSpace, offsetY = 1),
@@ -138,6 +141,7 @@ object SurfaceSpawningContextCalculator : FlooredSpawningContextCalculator<Surfa
world = input.world,
position = input.position.toImmutable(),
light = getLight(input),
skyLight = getSkyLight(input),
canSeeSky = getCanSeeSky(input),
influences = input.spawner.copyInfluences(),
height = getHeight(input, surroundingCondition, config.maxVerticalSpace / 2, offsetY = 1),
@@ -45,6 +45,7 @@ object SubmergedSpawningContextCalculator : AreaSpawningContextCalculator<Submer
world = input.world,
position = input.position.toImmutable(),
light = getLight(input),
skyLight = getSkyLight(input),
canSeeSky = getCanSeeSky(input),
influences = input.spawner.copyInfluences(),
height = getHeight(input, fluidCondition, ceil(config.maxVerticalSpace / 2F)),
@@ -42,9 +42,9 @@ open class PlayerLevelRangeInfluence(
val party = Cobblemon.storage.getParty(uuid)
previousRange = if (party.any()) {
val minimumLevel = party.minOf { it.level }
//val minimumLevel = party.minOf { it.level }
val maximumLevel = party.maxOf { it.level }
IntRange(max(minimumLevel - variation, 1), min(config.maxPokemonLevel, max(maximumLevel + variation, config.minimumLevelRangeMax)))
IntRange(max(maximumLevel - variation, 1), min(config.maxPokemonLevel, max(maximumLevel + variation, config.minimumLevelRangeMax)))
} else {
noPokemonRange
}
@@ -63,7 +63,8 @@ open class PlayerLevelRangeInfluence(
if (spawnLevelRange.isEmpty()){
spawnLevelRange = if (derivedLevelRange.first > playerLevelRange.last) {
derivedLevelRange.first..(derivedLevelRange.first + pokemonRangeWidth / 4F).toInt()
} else {
}
else {
(derivedLevelRange.first + 3 * pokemonRangeWidth / 4F).toInt()..derivedLevelRange.last
}
}
@@ -77,7 +77,7 @@ abstract class AreaSpawner(
val numberNearby = constrainedArea.world.getEntitiesByClass(
PokemonEntity::class.java,
areaBox
) { true }.size
) { pokemonEntity -> pokemonEntity.countsTowardsSpawnCap.get() }.size
val chunksCovered = CHUNK_REACH * CHUNK_REACH
if (numberNearby.toFloat() / chunksCovered >= Cobblemon.config.pokemonPerChunk) {
@@ -15,7 +15,7 @@ import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.selection.FlatSelector
import com.cobblemon.mod.common.api.spawning.selection.FlatContextWeightedSelector
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
import net.minecraft.entity.Entity
@@ -32,7 +32,7 @@ abstract class TickingSpawner(
var spawns: SpawnPool,
val manager: SpawnerManager
) : Spawner {
private var selector: SpawningSelector = FlatSelector()
private var selector: SpawningSelector = FlatContextWeightedSelector()
override val influences = mutableListOf<SpawningInfluence>()
override fun canSpawn() = active
@@ -25,6 +25,7 @@ import com.mongodb.client.model.ReplaceOptions
import net.minecraft.util.WorldSavePath
import org.bson.Document
import java.util.UUID
import java.util.Date
/**
* A [FileStoreAdapter] for MongoDB. This allows a [PokemonStore] to be serialized to a MongoDB database.
@@ -45,6 +46,7 @@ open class MongoDBStoreAdapter(
override fun save(storeClass: Class<out PokemonStore<*>>, uuid: UUID, serialized: JsonObject) {
val document = Document.parse(this.gson.toJson(serialized))
document["uuid"] = uuid.toString()
document["lastUpdated"] = Date()
val collection = getCollection(storeClass)
val filter = Document("uuid", uuid.toString())
collection.replaceOne(filter, document, ReplaceOptions().upsert(true))
@@ -67,7 +69,11 @@ open class MongoDBStoreAdapter(
if (document != null) {
val json = this.gson.fromJson(document.toJson(), JsonObject::class.java)
val store = storeClass.getConstructor(UUID::class.java).newInstance(uuid)
val store = try {
storeClass.getConstructor(UUID::class.java, UUID::class.java).newInstance(uuid, uuid)
} catch (exception: NoSuchMethodException) {
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
}
store.loadFromJSON(json)
return store
}
@@ -10,8 +10,8 @@ package com.cobblemon.mod.common.api.storage.player
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.net.messages.client.starter.SetClientPlayerDataPacket
import com.cobblemon.mod.common.util.cobblemonResource
import java.util.UUID
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -23,6 +23,7 @@ data class PlayerData(
var starterSelected: Boolean,
var starterUUID: UUID?,
var keyItems: MutableSet<Identifier>,
var battleTheme: Identifier?,
val extraData: MutableMap<String, PlayerDataExtension>,
) {
var advancementData: PlayerAdvancementData = PlayerAdvancementData()
@@ -40,6 +41,7 @@ data class PlayerData(
starterSelected = false,
starterUUID = null,
keyItems = mutableSetOf(),
battleTheme = CobblemonSounds.PVP_BATTLE.id,
extraData = mutableMapOf()
)
}
@@ -22,6 +22,8 @@ import net.minecraft.registry.tag.TagKey
@Suppress("HasPlatformType", "unused")
object CobblemonBlockTags {
@JvmField val ALL_HANGING_SIGNS = createTag("all_hanging_signs")
@JvmField val ALL_SIGNS = createTag("all_signs")
@JvmField val APRICORN_LEAVES = createTag("apricorn_leaves")
@JvmField val APRICORN_LOGS = createTag("apricorn_logs")
@JvmField val APRICORN_SAPLINGS = createTag("apricorn_saplings")
@@ -29,6 +31,7 @@ object CobblemonBlockTags {
@JvmField val BERRY_WILD_SOIL = createTag("berry_wild_soil")
@JvmField val BERRY_SOIL = createTag("berry_soil")
@JvmField val BERRY_REPLACEABLE = createTag("berry_replaceable")
@JvmField val CEILING_HANGING_SIGNS = createTag("ceiling_hanging_signs")
@JvmField val CROPS = createTag("crops")
@JvmField val DRIPSTONE_GROWABLE = createTag("dripstone_growable")
@JvmField val DRIPSTONE_REPLACEABLES = createTag("dripstone_replaceables")
@@ -36,10 +39,15 @@ object CobblemonBlockTags {
@JvmField val MEDICINAL_LEEK_PLANTABLE = createTag("medicinal_leek_plantable")
@JvmField val MINTS = createTag("mints")
@JvmField val ROOTS_SPREADABLE = createTag("roots_spreadable")
@JvmField val SIGNS = createTag("signs")
@JvmField val SMALL_FLOWERS = createTag("small_flowers")
@JvmField val SEES_SKY = createTag("sees_sky")
@JvmField val SNOW_BLOCK = createTag("snow_block")
@JvmField val ROOTS = createTag("roots")
@JvmField val STANDING_SIGNS = createTag("standing_signs")
@JvmField val WALL_HANGING_SIGNS = createTag("wall_hanging_signs")
@JvmField val WALL_SIGNS = createTag("wall_signs")
private fun createTag(name: String) = TagKey.of(RegistryKeys.BLOCK, cobblemonResource(name))
}
@@ -9,15 +9,17 @@
package com.cobblemon.mod.common.api.tags
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKeys
import net.minecraft.registry.tag.TagKey
/**
* A collection of the Cobblemon [TagKey]s related to the [Registry.ENTITY_TYPE].
* A collection of the Cobblemon [TagKey]s related to the [Registries.ENTITY_TYPE].
*
* @author Licious
* @since March 6th, 2023
*/
@Suppress("HasPlatformType", "unused")
object CobblemonEntityTypeTags {
@@ -27,6 +29,9 @@ object CobblemonEntityTypeTags {
@JvmField
val CANNOT_HAVE_NAME_TAG = create("cannot_have_name_tag")
@JvmField
val BOATS = create("boats")
private fun create(path: String) = TagKey.of(RegistryKeys.ENTITY_TYPE, cobblemonResource(path))
}
@@ -9,16 +9,17 @@
package com.cobblemon.mod.common.api.tags
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.registry.Registry
import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKeys
import net.minecraft.registry.tag.TagKey
/**
* A collection of the Cobblemon [TagKey]s related to the [Registry.ITEM].
* A collection of the Cobblemon [TagKey]s related to the [Registries.ITEM].
*
* @author Licious
* @since January 8th, 2023
*/
@Suppress("unused", "HasPlatformType")
object CobblemonItemTags {
@JvmField
@@ -27,11 +28,47 @@ object CobblemonItemTags {
val APRICORN_SEEDS = create("apricorn_seeds")
@JvmField
val APRICORNS = create("apricorns")
/**
* This tag is only used for a Torterra aspect based easter egg evolution at the moment.
* It simply includes the 'minecraft:azalea' and 'minecraft:flowering_azalea' items by default.
*/
@JvmField
val AZALEA_TREE = create("azalea_tree")
@JvmField
val BERRIES = create("berries")
@JvmField
val BOATS = create("boats")
@JvmField
val COBBLEMON_SEEDS = create("cobblemon_seeds")
@JvmField
val EVOLUTION_ITEMS = create("evolution_items")
@JvmField
val EVOLUTION_STONES = create("evolution_stones")
@JvmField
val EXPERIENCE_CANDIES = create("experience_candies")
@JvmField
val HANGING_SIGNS = create("hanging_signs")
@JvmField
val HERBS = create("herbs")
@JvmField
val MINT_LEAF = create("mint_leaf")
@JvmField
val MINTS = create("mints")
@JvmField
val MUTATED_BERRIES = create("mutated_berries")
@JvmField
val PLANTS = create("plants")
@JvmField
val POKEBALLS = create("poke_balls")
@JvmField
val PROTEIN_INGREDIENTS = create("protein_ingredients")
@JvmField
val SEEDS = create("seeds")
@JvmField
val SIGNS = create("signs")
@JvmField
val ZINC_INGREDIENTS = create("zinc_ingredients")
@JvmField
val ANY_HELD_ITEM = create("held/is_held_item")
@JvmField
val EXPERIENCE_SHARE = create("held/experience_share")
@@ -54,19 +91,11 @@ object CobblemonItemTags {
@JvmField
val POWER_WEIGHT = create("held/power_weight")
@JvmField
val EVOLUTION_STONES = create("evolution_stones")
val CONSUMED_IN_NPC_BATTLE = create("held/consumed_in_npc_battle")
@JvmField
val EVOLUTION_ITEMS = create("evolution_items")
val CONSUMED_IN_PVP_BATTLE = create("held/consumed_in_pvp_battle")
@JvmField
val MINTS = create("mints")
@JvmField
val MINT_LEAVES = create("mint_leaves")
/**
* This tag is only used for a Torterra aspect based easter egg evolution at the moment.
* It simply includes the 'minecraft:azalea' and 'minecraft:flowering_azalea' items by default.
*/
val AZALEA_TREE = create("azalea_tree")
val CONSUMED_IN_WILD_BATTLE = create("held/consumed_in_wild_battle")
private fun create(path: String) = TagKey.of(RegistryKeys.ITEM, cobblemonResource(path))
@@ -9,16 +9,16 @@
package com.cobblemon.mod.common.battles
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.battles.BattleStartedPreEvent
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getBattleTheme
import com.cobblemon.mod.common.util.getPlayer
import com.cobblemon.mod.common.util.party
import java.util.Optional
@@ -63,18 +63,14 @@ object BattleBuilder {
}
return if (errors.isEmpty) {
CobblemonEvents.BATTLE_STARTED_PRE.postThen(
BattleStartedPreEvent(listOf(player1Actor, player2Actor), battleFormat, true, false, false))
{
return SuccessfulBattleStart(
BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(player1Actor),
side2 = BattleSide(player2Actor)
)
)
BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(player1Actor),
side2 = BattleSide(player2Actor)
).ifSuccessful {
player1Actor.battleTheme = player2.getBattleTheme()
player2Actor.battleTheme = player1.getBattleTheme()
}
errors
} else {
errors
}
@@ -125,20 +121,16 @@ object BattleBuilder {
}
return if (errors.isEmpty) {
CobblemonEvents.BATTLE_STARTED_PRE.postThen(
BattleStartedPreEvent(listOf(playerActor, wildActor), battleFormat, false, false, true))
{
val battle = BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(playerActor),
side2 = BattleSide(wildActor)
)
BattleRegistry.startBattle(
battleFormat = battleFormat,
side1 = BattleSide(playerActor),
side2 = BattleSide(wildActor)
).ifSuccessful {
if (!cloneParties) {
pokemonEntity.battleId.set(Optional.of(battle.battleId))
pokemonEntity.battleId.set(Optional.of(it.battleId))
}
return SuccessfulBattleStart(battle)
playerActor.battleTheme = pokemonEntity.getBattleTheme()
}
errors
} else {
errors
}
@@ -178,12 +170,21 @@ interface BattleStartError {
requiredCount: Int,
hadCount: Int
) = InsufficientPokemonError(player, requiredCount, hadCount)
fun canceledByEvent(reason: MutableText?) = CanceledError(reason)
}
}
enum class CommonBattleStartError : BattleStartError {
}
class CanceledError(
val reason: MutableText?
): BattleStartError {
override fun getMessageFor(entity: Entity) = reason ?: battleLang("error.canceled")
}
class InsufficientPokemonError(
val player: ServerPlayerEntity,
val requiredCount: Int,
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
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
import com.cobblemon.mod.common.api.events.battles.BattleStartedPreEvent
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.status.Statuses
@@ -145,17 +146,11 @@ object BattleRegistry {
return team.joinToString("]")
}
fun startBattle(
battleFormat: BattleFormat,
side1: BattleSide,
side2: BattleSide
): PokemonBattle {
val battle = PokemonBattle(battleFormat, side1, side2)
battleMap[battle.battleId] = battle
private fun startShowdown(battle: PokemonBattle) {
// Build request message
val messages = mutableListOf<String>()
messages.add(">start { \"format\": ${battleFormat.toFormatJSON()} }")
messages.add(">start { \"format\": ${battle.format.toFormatJSON()} }")
/*
* Showdown IDs are like p1, p2, p3, etc. Showdown uses these keys to identify who is doing what to whom.
@@ -174,19 +169,17 @@ object BattleRegistry {
var actorIndex = 1
for (actor in battle.side1.actors) {
actor.showdownId = "p$actorIndex"
actor.battle = battle
actorIndex += 2
}
actorIndex = 2
for (actor in battle.side2.actors) {
actor.showdownId = "p$actorIndex"
actor.battle = battle
actorIndex += 2
}
for (actor in battle.actors) {
repeat(battleFormat.battleType.slotsPerActor) {
repeat(battle.format.battleType.slotsPerActor) {
actor.activePokemon.add(ActiveBattlePokemon(actor))
}
val entities = actor.pokemonList.mapNotNull { it.entity }
@@ -205,8 +198,25 @@ object BattleRegistry {
// Compiles the request and sends it off
ShowdownService.service.startBattle(battle, messages.toTypedArray())
CobblemonEvents.BATTLE_STARTED_POST.post(BattleStartedPostEvent(battle))
return battle
}
fun startBattle(
battleFormat: BattleFormat,
side1: BattleSide,
side2: BattleSide,
silent: Boolean = false
): BattleStartResult {
val battle = PokemonBattle(battleFormat, side1, side2)
if (silent) return SuccessfulBattleStart(battle)
val preBattleEvent = BattleStartedPreEvent(battle)
CobblemonEvents.BATTLE_STARTED_PRE.postThen(preBattleEvent) {
battleMap[battle.battleId] = battle
startShowdown(battle)
CobblemonEvents.BATTLE_STARTED_POST.post(BattleStartedPostEvent(battle))
return SuccessfulBattleStart(battle)
}
return ErroredBattleStart(mutableSetOf(BattleStartError.canceledByEvent(preBattleEvent.reason)))
}
fun closeBattle(battle: PokemonBattle) {
@@ -221,6 +231,10 @@ object BattleRegistry {
return battleMap.values.find { it.getActor(serverPlayerEntity) != null }
}
fun getBattleByParticipatingPlayerId(playerId: UUID): PokemonBattle? {
return battleMap.values.find { playerId in it.playerUUIDs }
}
fun tick() {
battleMap.forEachValue(Long.MAX_VALUE) { it.tick() }
}
@@ -206,7 +206,7 @@ data class SwitchActionResponse(var newPokemonId: UUID) : ShowdownActionResponse
val pokemon = activeBattlePokemon.actor.pokemonList.find { it.uuid == newPokemonId }
return when {
pokemon == null -> false // No such Pokémon
pokemon.health <= 0 -> false // Pokémon is dead
(!activeBattlePokemon.actor.request?.side?.pokemon?.get(0)?.reviving!! && pokemon.health <= 0) -> false // Checks if the active Pokémon is reviving, if so ignore this check. If not, return false if dead
showdownMoveSet != null && showdownMoveSet.trapped -> false // You're not allowed to switch
activeBattlePokemon.actor.getSide().activePokemon.any { it.battlePokemon?.uuid == newPokemonId } -> false // Pokémon is already sent out
else -> true
@@ -35,6 +35,7 @@ import com.cobblemon.mod.common.battles.interpreter.ContextManager
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.net.messages.client.battle.*
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgress
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
@@ -47,6 +48,7 @@ import net.minecraft.server.world.ServerWorld
import net.minecraft.text.MutableText
import net.minecraft.text.Text
@Suppress("KotlinPlaceholderCountMatchesArgumentCount", "UNUSED_PARAMETER")
object ShowdownInterpreter {
private val updateInstructions = mutableMapOf<String, (PokemonBattle, BattleMessage, MutableList<String>) -> Unit>()
private val sideUpdateInstructions = mutableMapOf<String, (PokemonBattle, BattleActor, BattleMessage) -> Unit>()
@@ -81,20 +83,23 @@ object ShowdownInterpreter {
updateInstructions["|-mustrecharge|"] = this::handleRechargeInstructions
updateInstructions["|-fail|"] = this::handleFailInstruction
updateInstructions["|-start|"] = this::handleStartInstructions
updateInstructions["|-block|"] = this::handleBlockInstructions
updateInstructions["|-activate|"] = this::handleActivateInstructions
updateInstructions["|-curestatus|"] = this::handleCureStatusInstruction
updateInstructions["|-fieldstart|"] = this::handleFieldStartInstructions
updateInstructions["|-fieldend|"] = this::handleFieldEndInstructions
updateInstructions["|-ability|"] = this::handleAbilityInstructions
//To-Do updateInstructions["|-endability|"] = this::handleEndAbilityInstruction
updateInstructions["|-endability|"] = this::handleEndAbilityInstruction
updateInstructions["|-nothing"] = { battle, _, _ ->
battle.dispatchGo { battle.broadcastChatMessage(battleLang("nothing")) }
}
updateInstructions["|-clearallboost"] = this::handleClearAllBoostInstructions
updateInstructions["|-singleturn|"] = this::handleSingleTurnInstruction
updateInstructions["|-singlemove|"] = this::handleSingleMoveInstruction
updateInstructions["|-transform|"] = this::handleTransformInstruction
updateInstructions["|-prepare|"] = this::handlePrepareInstruction
updateInstructions["|-swapboost"] = this::handleSwapBoostInstruction
updateInstructions["|-copyboost|"] = this::handleCopyBoostInstruction
updateInstructions["|-swapsideconditions|"] = this::handleSilently
updateInstructions["|-unboost|"] = { battle, line, remainingLines -> boostInstruction(battle, line, remainingLines, false) }
updateInstructions["|-boost|"] = { battle, line, remainingLines -> boostInstruction(battle, line, remainingLines, true) }
@@ -102,6 +107,7 @@ object ShowdownInterpreter {
updateInstructions["|t:|"] = {_, _, _ -> }
updateInstructions["|pp_update|"] = this::handlePpUpdateInstruction
updateInstructions["|-immune"] = this::handleImmuneInstruction
updateInstructions["|-invertboost|"] = this::handleInvertBoostInstruction
updateInstructions["|-status|"] = this::handleStatusInstruction
updateInstructions["|-end|"] = this::handleEndInstruction
updateInstructions["|-miss|"] = this::handleMissInstruction
@@ -473,12 +479,10 @@ object ShowdownInterpreter {
private fun handleTurnInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
if (!battle.started) {
battle.started = true
battle.actors.forEach { actor ->
if (actor.uuid.getPlayer() != null) {
val initializePacket = BattleInitializePacket(battle, actor.getSide())
actor.sendUpdate(initializePacket)
actor.sendUpdate(BattleMusicPacket(battle))
}
battle.actors.filterIsInstance<PlayerBattleActor>().forEach { actor ->
val initializePacket = BattleInitializePacket(battle, actor.getSide())
actor.sendUpdate(initializePacket)
actor.sendUpdate(BattleMusicPacket(actor.battleTheme))
}
battle.actors.forEach { actor ->
actor.sendUpdate(BattleSetTeamPokemonPacket(actor.pokemonList.map { it.effectedPokemon }))
@@ -652,6 +656,34 @@ object ShowdownInterpreter {
}
}
/**
* Format:
* |-invertboost|POKEMON|MOVE
*
* The POKEMON had its stat changes inverted.
*/
private fun handleInvertBoostInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
battle.dispatchWaiting {
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchWaiting
val name = pokemon.getName()
battle.broadcastChatMessage(battleLang("invertboost", name))
// update and invert BOOST and UNBOOST contexts
val context = getContextFromAction(message, BattleContext.Type.BOOST, battle)
val newUnboosts = pokemon.contextManager.get(BattleContext.Type.BOOST)?.map {
BasicContext(it.id, context.turn, BattleContext.Type.UNBOOST, context.origin)
}?.toTypedArray()
val newBoosts = pokemon.contextManager.get(BattleContext.Type.UNBOOST)?.map {
BasicContext(it.id, context.turn, BattleContext.Type.BOOST, context.origin)
}?.toTypedArray()
pokemon.contextManager.clear(BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
newBoosts?.let { pokemon.contextManager.add(*it) }
newUnboosts?.let { pokemon.contextManager.add(*it) }
battle.minorBattleActions[pokemon.uuid] = message
}
}
/**
* Format:
* |move|POKEMON|MOVE|TARGET
@@ -779,7 +811,10 @@ object ShowdownInterpreter {
battle.broadcastChatMessage(battleLang("crit").yellow())
this.lastCauser[battle.battleId]?.let { message ->
val battlePokemon = message.getBattlePokemon(0, battle) ?: return@let
battlePokemon.criticalHits++
if (LastBattleCriticalHitsEvolutionProgress.supports(battlePokemon.effectedPokemon)) {
val progress = battlePokemon.effectedPokemon.evolutionProxy.current().progressFirstOrCreate({ it is LastBattleCriticalHitsEvolutionProgress }) { LastBattleCriticalHitsEvolutionProgress() }
progress.updateProgress(LastBattleCriticalHitsEvolutionProgress.Progress(progress.currentProgress().amount + 1))
}
}
battle.minorBattleActions[pokemon.uuid] = message
}
@@ -822,10 +857,32 @@ object ShowdownInterpreter {
*
* The specified ACTION has failed against the POKEMON targetted.
*/
private fun handleFailInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>){
private fun handleFailInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
battle.dispatchWaiting(1.5F){
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchWaiting
battle.broadcastChatMessage(battleLang("fail").red())
val pokemonName = pokemon.getName()
val effectID = message.effectAt(1)?.id
val cause = message.effect("from")
val of = message.getSourceBattlePokemon(battle)
val lang = when (effectID) {
null, "burnup", "doubleshock" -> battleLang("fail") // Moves that use default fail lang. (Null included for moves that fail with no effect, for example: Baton Pass.)
"shedtail" -> battleLang("fail.substitute", pokemonName)
"hyperspacefury", "aurawheel" -> battleLang("fail.darkvoid", pokemonName) // Moves that can only be used by one species and fail when any others try
"corrosivegas" -> battleLang("fail.healblock", pokemonName)
"dynamax" -> battleLang("fail.grassknot", pokemonName) // Covers weight moves that fail against dynamaxed Pokémon
"unboost" -> {
val statKey = message.argumentAt(2)
val stat = statKey?.let { getStat(it).displayName }
if (stat != null) {
battleLang("fail.$effectID.single", pokemonName, stat)
} else {
battleLang("fail.$effectID", pokemonName)
}
}
else -> battleLang("fail.$effectID", pokemonName)
}
battle.broadcastChatMessage(lang.red())
battle.minorBattleActions[pokemon.uuid] = message
}
}
@@ -889,6 +946,11 @@ object ShowdownInterpreter {
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatch GO
val effectID = message.effectAt(1)?.id ?: return@dispatch GO
val optionalEffect = message.effect()
val optionalPokemon = message.getSourceBattlePokemon(battle)
val optionalPokemonName = optionalPokemon?.getName()
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKOWN")
// skip adding contexts for every time the perish counter decrements
if (!effectID.contains("perish")) {
// don't need to add unique: showdown won't send -start instruction if volatile status is already present
@@ -897,13 +959,17 @@ object ShowdownInterpreter {
battle.minorBattleActions[pokemon.uuid] = message
if (!message.hasOptionalArgument("silent")) {
val lang = when (effectID) {
"confusion", "perish3" -> return@dispatch GO // Skip
"perish2", "perish1", "perish0" -> battleLang("start.perish", pokemon.getName(), effectID.last().digitToInt())
"dynamax" -> battleLang("start.${message.effectAt(2)?.id ?: effectID}", pokemon.getName()).yellow()
"curse" -> battleLang("start.curse", message.getSourceBattlePokemon(battle)!!.getName(), pokemon.getName())
else -> battleLang("start.$effectID", pokemon.getName())
}
val lang = if (optionalEffect?.id == "reflecttype" && optionalPokemonName != null)
battleLang("start.reflecttype", pokemon.getName(), optionalPokemonName)
else
when (effectID) {
"confusion", "perish3" -> return@dispatch GO // Skip
"perish2", "perish1", "perish0",
"stockpile1", "stockpile2", "stockpile3" -> battleLang("start.${effectID.dropLast(1)}", pokemon.getName(), effectID.last().digitToInt())
"dynamax" -> battleLang("start.${message.effectAt(2)?.id ?: effectID}", pokemon.getName()).yellow()
"curse" -> battleLang("start.curse", message.getSourceBattlePokemon(battle)!!.getName(), pokemon.getName())
else -> battleLang("start.$effectID", pokemon.getName(), extraEffect)
}
battle.broadcastChatMessage(lang)
}
WaitDispatch(1F)
@@ -920,7 +986,7 @@ object ShowdownInterpreter {
battle.dispatchWaiting(1.5F) {
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchWaiting
val pokemonName = pokemon.getName()
val sourceName = message.getSourceBattlePokemon(battle)?.getName() ?: return@dispatchWaiting
val sourceName = message.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKOWN")
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
val lang = battleLang("singleturn.$effectID", pokemonName, sourceName)
battle.broadcastChatMessage(lang)
@@ -928,6 +994,25 @@ object ShowdownInterpreter {
}
}
/**
* Format:
* |-transform|POKEMON|POKEMON
*
* The Pokémon POKEMON used Transform to turn into Target Pokemon POKEMON
*/
private fun handleTransformInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
battle.dispatchWaiting(1.5F) {
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchWaiting
val pokemonName = pokemon.getName()
val targetPokemon = message.getBattlePokemon(1, battle) ?: return@dispatchWaiting
val targetPokemonName = targetPokemon.getName()
val lang = battleLang("transform", pokemonName, targetPokemonName)
battle.broadcastChatMessage(lang)
battle.minorBattleActions[pokemon.uuid] = message
}
}
/**
* Format:
* |-singlemove|POKEMON|MOVE
@@ -945,6 +1030,43 @@ object ShowdownInterpreter {
}
}
/**
* Format:
* |-endability|POKEMON
*
* The Pokémon POKEMON's Ability was surpressed
*/
private fun handleEndAbilityInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
battle.dispatchWaiting(1.5F) {
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchWaiting
val pokemonName = pokemon.getName()
val lang = battleLang("endability", pokemonName)
battle.broadcastChatMessage(lang)
battle.minorBattleActions[pokemon.uuid] = message
}
}
/**
* Format:
* |-block|POKEMON|EFFECT|MOVE|ATTACKER
*
* An effect targeted at POKEMON was blocked by EFFECT. This may optionally specify that the effect was a MOVE from ATTACKER.
*
* (of)SOURCE will note the owner of the EFFECT, in the case that it's not EFFECT (for instance, an ally with Aroma Veil.)
*/
private fun handleBlockInstructions(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
battle.dispatchWaiting(1.5F) {
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchWaiting
val pokemonName = pokemon.getName()
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
val lang = battleLang("block.$effectID", pokemonName)
battle.broadcastChatMessage(lang)
battle.minorBattleActions[pokemon.uuid] = message
}
}
/**
* Format:
* |-activate|POKEMON|EFFECT
@@ -956,6 +1078,7 @@ object ShowdownInterpreter {
val pokemonName = pokemon.getName()
val sourceName = message.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKOWN")
val effect = message.effectAt(1) ?: return
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKOWN")
broadcastOptionalAbility(battle, effect, pokemonName)
battle.dispatch{
@@ -966,7 +1089,7 @@ object ShowdownInterpreter {
// Includes a 3rd argument being the magnitude level as a number
"magnitude" -> battleLang("activate.magnitude", message.argumentAt(2)?.toIntOrNull() ?: 1)
// Includes spited move and the PP it was reduced by
"spite" -> battleLang("activate.spite", pokemonName, message.argumentAt(2)!!, message.argumentAt(3)!!)
"spite", "eeriespell" -> battleLang("activate.spite", pokemonName, extraEffect, message.argumentAt(3)!!)
// Don't need additional lang, announced elsewhere
"toxicdebris", "shedskin" -> return@dispatch GO
// Add activation to each Pokemon's history
@@ -974,14 +1097,10 @@ object ShowdownInterpreter {
battle.activePokemon.mapNotNull { it.battlePokemon?.uuid }.forEach { battle.minorBattleActions[it] = message }
battleLang("activate.destinybond", pokemonName)
}
// Includes revealed move
"forewarn" -> {
val moveName = message.moveAt(2)?.displayName ?: run { println(message.argumentAt(2)); "(Unrecognized: ${message.argumentAt(2)})".text() }
battleLang("activate.forewarn", sourceName, moveName)
}
"focussash", "focusband" -> battleLang("activate.focusband", pokemonName, message.effectAt(1)!!.typelessData)
"focussash", "focusband" -> battleLang("activate.focusband", pokemonName, effect.typelessData)
"maxguard", "protect" -> battleLang("activate.protect", pokemonName)
else -> battleLang("activate.${effect.id}", pokemonName, sourceName)
"shadowforce", "hyperspacefury", "hyperspacehole" -> battleLang("activate.phantomforce", pokemonName)
else -> battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
}
battle.broadcastChatMessage(lang)
WaitDispatch(1F)
@@ -1047,7 +1166,7 @@ object ShowdownInterpreter {
/**
* Format:
* |-ability|POKEMON|ABILITY|[from]EFFECT
* |-ability|POKEMON|ABILITY|(from)EFFECT
*
* The ABILITY of the POKEMON has been changed due to a move/ability EFFECT.
*
@@ -1060,15 +1179,28 @@ object ShowdownInterpreter {
val pokemon = message.getBattlePokemon(0, battle) ?: return
val pokemonName = pokemon.getName()
val effect = message.effectAt(1) ?: return
broadcastAbility(battle, effect, pokemonName)
val optionalEffect = message.effect()
val optionalPokemon = message.getSourceBattlePokemon(battle)
val optionalPokemonName = optionalPokemon?.getName()
// If there is an optional effect causing the activation, broadcast that instead of the standard effect
if (optionalEffect != null) {
broadcastAbility(battle, optionalEffect, pokemonName)
} else {
broadcastAbility(battle, effect, pokemonName)
}
battle.dispatch {
this.lastCauser[battle.battleId] = message
val lang = when (effect.id) {
"sturdy", "unnerve", "anticipation" -> battleLang("ability.${effect.id}", pokemonName) // Unique message
"airlock", "cloudnine" -> battleLang("ability.airlock") // Cloud Nine shares the same text as Air Lock
else -> null // Effect broadcasted by a succeeding instruction
val lang = when (optionalEffect?.id) {
"trace" -> optionalPokemonName?.let { battleLang("ability.trace", pokemonName, it, effect.typelessData) }
"receiver", "powerofalchemy" -> optionalPokemonName?.let { battleLang("ability.receiver", it, effect.typelessData) } // Receiver and Power of Alchemy share the same text
else -> when (effect.id) {
"sturdy", "unnerve", "anticipation" -> battleLang("ability.${effect.id}", pokemonName) // Unique message
"airlock", "cloudnine" -> battleLang("ability.airlock") // Cloud Nine shares the same text as Air Lock
else -> null // Effect broadcasted by a succeeding instruction
}
}
battle.minorBattleActions[pokemon.uuid] = message
@@ -1115,6 +1247,8 @@ object ShowdownInterpreter {
}
}
/**
* Format:
* |-swapboost|SOURCE|TARGET|STATS
@@ -1127,7 +1261,11 @@ object ShowdownInterpreter {
val pokemonName = pokemon.getName()
val targetPokemon = message.getBattlePokemon(1, battle) ?: return@dispatchWaiting
val targetPokemonName = targetPokemon.getName()
val lang = battleLang("swapboost.generic", pokemonName, targetPokemonName)
val effectID = message.effect()?.id ?: return@dispatchWaiting
val lang = when (effectID) {
"guardswap", "powerswap", "heartswap" -> battleLang("swapboost.$effectID", pokemonName)
else -> battleLang("swapboost.generic", pokemonName, targetPokemonName)
}
battle.broadcastChatMessage(lang)
pokemon.contextManager.swap(targetPokemon.contextManager, BattleContext.Type.BOOST)
@@ -1136,6 +1274,26 @@ object ShowdownInterpreter {
}
}
/**
* Format:
* |-copyboost|SOURCE|TARGET|&#91from&#93EFFECT
*
* Copies any stat changes from the TARGET Pokémon to the SOURCE Pokémon due to EFFECT.
*/
private fun handleCopyBoostInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
battle.dispatchWaiting {
val pokemon = message.getBattlePokemon(0, battle) ?: return@dispatchWaiting
val pokemonName = pokemon.getName()
val targetPokemon = message.getBattlePokemon(1, battle) ?: return@dispatchWaiting
val targetPokemonName = targetPokemon.getName()
val lang = battleLang("copyboost.generic", pokemonName, targetPokemonName)
battle.broadcastChatMessage(lang)
pokemon.contextManager.copy(targetPokemon.contextManager, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
battle.minorBattleActions[pokemon.uuid] = message
}
}
/**
* Format:
* |-end|POKEMON|EFFECT
@@ -1412,6 +1570,8 @@ object ShowdownInterpreter {
lang("status.$status.hurt", pokemonName)
}
"aftermath" -> battleLang("damage.generic", pokemonName)
"chloroblast", "steelbeam" -> battleLang("damage.mindblown", pokemonName)
"jumpkick" -> battleLang("damage.highjumpkick", pokemonName)
else -> battleLang("damage.${effect.id}", pokemonName, sourceName)
}
battle.broadcastChatMessage(lang.red())
@@ -1428,7 +1588,7 @@ object ShowdownInterpreter {
val maxHealth = newHealth.split("/")[1].toInt()
val difference = maxHealth - remainingHealth
newHealthRatio = remainingHealth.toFloat() / maxHealth
battle.dispatch {
battle.dispatchToFront {
battlePokemon.effectedPokemon.currentHealth = remainingHealth
if (difference > 0) {
battlePokemon.effectedPokemon.let { pokemon ->
@@ -1444,6 +1604,7 @@ object ShowdownInterpreter {
}
privateMessage.pnxAndUuid(0)?.let { (pnx, _) -> battle.sendSidedUpdate(actor, BattleHealthChangePacket(pnx, remainingHealth.toFloat()), BattleHealthChangePacket(pnx, newHealthRatio)) }
battle.minorBattleActions[battlePokemon.uuid] = privateMessage
WaitDispatch(1F)
}
@@ -1502,7 +1663,7 @@ object ShowdownInterpreter {
/**
* Format:
* |-item|POKEMON|ITEM|[from]EFFECT
* |-item|POKEMON|ITEM|(from)EFFECT
*
* The ITEM held by the POKEMON has been changed or revealed due to a move or ability EFFECT.
*
@@ -1525,7 +1686,7 @@ object ShowdownInterpreter {
/**
* Format:
* |-enditem|POKEMON|ITEM|[from]EFFECT
* |-enditem|POKEMON|ITEM|(from)EFFECT
*
* The ITEM held by POKEMON has been destroyed by a move or ability, and it now holds no item.
*
@@ -1536,11 +1697,12 @@ object ShowdownInterpreter {
*/
fun handleEndItemInstruction(battle: PokemonBattle, message: BattleMessage, remainingLines: MutableList<String>) {
battle.dispatchGo {
// All logic regarding broadcasting battle messages is handled in CobblemonHeldItemManager
val battlePokemon = message.getBattlePokemon(0, battle) ?: return@dispatchGo
val item = message.effectAt(1) ?: return@dispatchGo
val itemEffect = message.effectAt(1) ?: return@dispatchGo
battlePokemon.heldItemManager.handleEndInstruction(battlePokemon, battle, message)
battle.minorBattleActions[battlePokemon.uuid] = message
battlePokemon.contextManager.remove(item.id, BattleContext.Type.ITEM)
battlePokemon.contextManager.remove(itemEffect.id, BattleContext.Type.ITEM)
if (message.hasOptionalArgument("eat")) {
battlePokemon.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F)
}
@@ -1559,7 +1721,7 @@ object ShowdownInterpreter {
val rawHpAndStatus = privateMessage.argumentAt(1)?.split(" ") ?: return
val rawHpRatio = rawHpAndStatus.getOrNull(0) ?: return
val newHealth = rawHpRatio.split("/").map { it.toFloatOrNull() ?: return }
val newHealthRatio = rawHpRatio.split("/").map { it.toFloatOrNull()?.div(100) ?: return }
val newHealthRatio = rawHpRatio.split("/").map { it.toFloatOrNull()?.div(newHealth[1]) ?: return }
val effect = privateMessage.effect()
val pokemonName = battlePokemon.getName()
broadcastOptionalAbility(battle, effect, pokemonName)
@@ -1607,7 +1769,7 @@ object ShowdownInterpreter {
// This part is not always present
val rawStatus = rawHpAndStatus.getOrNull(1) ?: return@dispatchWaiting
val status = Statuses.getStatus(rawStatus) ?: return@dispatchWaiting
if (status is PersistentStatus) {
if (status is PersistentStatus && battlePokemon.effectedPokemon.status?.status != status) {
battlePokemon.effectedPokemon.applyStatus(status)
if (pnx != null) {
battle.sendUpdate(BattlePersistentStatusPacket(pnx, status))
@@ -1672,7 +1834,9 @@ object ShowdownInterpreter {
message.hasOptionalArgument("zeffect") -> battleLang("clearallnegativeboost.zeffect", pokemonName)
else -> battleLang("clearallnegativeboost", pokemonName)
}
battle.broadcastChatMessage(lang)
if (!message.hasOptionalArgument("silent")) {
battle.broadcastChatMessage(lang)
}
battlePokemon.contextManager.clear(BattleContext.Type.UNBOOST)
battle.minorBattleActions[battlePokemon.uuid] = message
@@ -17,10 +17,12 @@ import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.pokemon.experience.BattleExperienceSource
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getPlayer
import java.util.UUID
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundEvent
import net.minecraft.text.MutableText
class PlayerBattleActor(
@@ -31,6 +33,14 @@ class PlayerBattleActor(
override val entity: ServerPlayerEntity?
get() = this.uuid.getPlayer()
/** The [SoundEvent] to play to the player during a battle. Will start playing as soon as the battle starts. */
var battleTheme: SoundEvent? = null
set(value) {
if (field != value && this.battle.started)
this.sendUpdate(BattleMusicPacket(value))
field = value
}
override fun getName(): MutableText = this.entity?.name?.copy() ?: "Offline Player".red()
override fun nameOwned(name: String): MutableText = battleLang("owned_pokemon", this.getName(), name)
override val type = ActorType.PLAYER
@@ -73,6 +73,15 @@ class ContextManager {
}
}
/** Copies all the [BattleContext]s belonging to the [bucketTypes] buckets of the [with] manager's respective buckets. */
fun copy(with: ContextManager, vararg bucketTypes: BattleContext.Type) {
bucketTypes.forEach { bucketType ->
val newContexts = with.buckets[bucketType]?.toMutableList()
this.clear(bucketType)
newContexts?.let { this.add(*it.toTypedArray()) }
}
}
/** Gets all [BattleContext]s belonging to the [bucketType] bucket. */
fun get(bucketType: BattleContext.Type) : Collection<BattleContext>? {
return buckets[bucketType]
@@ -64,11 +64,6 @@ open class BattlePokemon(
/** A set of all the BattlePokemon that they faced during the battle (for exp purposes) */
val facedOpponents = mutableSetOf<BattlePokemon>()
/**
* A counter of critical hits during this battle, this is used for an evolution requirement.
*/
var criticalHits: Int = 0
/**
* The [HeldItemManager] backing this [BattlePokemon].
*/
@@ -89,7 +84,12 @@ open class BattlePokemon(
}
fun isSentOut() = actor.battle.activePokemon.any { it.battlePokemon == this }
fun canBeSentOut() = !isSentOut() && !willBeSwitchedIn && health > 0
fun canBeSentOut() =
if (actor.request?.side?.pokemon?.get(0)?.reviving == true) {
!isSentOut() && !willBeSwitchedIn && health <= 0
} else {
!isSentOut() && !willBeSwitchedIn && health > 0
}
fun writeVariables(struct: VariableStruct) {
effectedPokemon.writeVariables(struct)
@@ -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.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.block.entity.HangingSignBlockEntity
import net.minecraft.util.math.BlockPos
class CobblemonHangingSignBlockEntity(pos: BlockPos, state: BlockState) : HangingSignBlockEntity(pos, state) {
override fun getType(): BlockEntityType<*> = CobblemonBlockEntities.HANGING_SIGN
}
@@ -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.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.block.entity.SignBlockEntity
import net.minecraft.util.math.BlockPos
class CobblemonSignBlockEntity(pos: BlockPos, state: BlockState) : SignBlockEntity(pos, state) {
override fun getType(): BlockEntityType<*> = CobblemonBlockEntities.SIGN
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.sign
import com.cobblemon.mod.common.block.entity.CobblemonHangingSignBlockEntity
import net.minecraft.block.BlockState
import net.minecraft.block.HangingSignBlock
import net.minecraft.block.WoodType
import net.minecraft.block.entity.BlockEntity
import net.minecraft.util.math.BlockPos
class CobblemonHangingSignBlock(settings: Settings, woodType: WoodType) : HangingSignBlock(settings, woodType) {
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity = CobblemonHangingSignBlockEntity(pos, state)
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.sign
import com.cobblemon.mod.common.block.entity.CobblemonSignBlockEntity
import net.minecraft.block.BlockState
import net.minecraft.block.SignBlock
import net.minecraft.block.WoodType
import net.minecraft.block.entity.BlockEntity
import net.minecraft.util.math.BlockPos
class CobblemonSignBlock(settings: Settings, woodType: WoodType) : SignBlock(settings, woodType) {
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity = CobblemonSignBlockEntity(pos, state)
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.sign
import com.cobblemon.mod.common.block.entity.CobblemonHangingSignBlockEntity
import net.minecraft.block.BlockState
import net.minecraft.block.WallHangingSignBlock
import net.minecraft.block.WoodType
import net.minecraft.block.entity.BlockEntity
import net.minecraft.util.math.BlockPos
class CobblemonWallHangingSignBlock(settings: Settings, woodType: WoodType) : WallHangingSignBlock(settings, woodType) {
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity = CobblemonHangingSignBlockEntity(pos, state)
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.sign
import com.cobblemon.mod.common.block.entity.CobblemonSignBlockEntity
import net.minecraft.block.BlockState
import net.minecraft.block.WallSignBlock
import net.minecraft.block.WoodType
import net.minecraft.block.entity.BlockEntity
import net.minecraft.util.math.BlockPos
class CobblemonWallSignBlock(settings: Settings, woodType: WoodType) : WallSignBlock(settings, woodType) {
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity = CobblemonSignBlockEntity(pos, state)
}
@@ -9,74 +9,47 @@
package com.cobblemon.mod.common.brewing
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.brewing.ingredient.CobblemonIngredient
import com.cobblemon.mod.common.brewing.ingredient.CobblemonItemIngredient
import com.cobblemon.mod.common.brewing.ingredient.CobblemonPotionIngredient
import net.minecraft.item.Item
import net.minecraft.potion.Potion
import net.minecraft.potion.Potions
import net.minecraft.recipe.BrewingRecipeRegistry
import net.minecraft.recipe.Ingredient
object BrewingRecipes {
// Put things here if you want them to be add-able to the bottom of the brewing stand (like where potions go)
@JvmField
val brewableItems = mutableListOf(
CobblemonItems.MEDICINAL_BREW,
CobblemonItems.POTION,
CobblemonItems.SUPER_POTION,
CobblemonItems.HYPER_POTION,
CobblemonItems.MAX_POTION,
CobblemonItems.FULL_RESTORE,
CobblemonItems.FULL_HEAL,
CobblemonItems.ANTIDOTE,
CobblemonItems.AWAKENING,
CobblemonItems.BURN_HEAL,
CobblemonItems.ICE_HEAL,
CobblemonItems.PARALYZE_HEAL,
CobblemonItems.ETHER,
CobblemonItems.MAX_ETHER,
CobblemonItems.ELIXIR,
CobblemonItems.MAX_ELIXIR
)
fun registerPotionTypes() {
brewableItems.forEach { item ->
BrewingRecipeRegistry.POTION_TYPES.add(Ingredient.ofItems(item))
}
}
fun getPotionRecipes(): List<Triple<Potion, Ingredient, Potion>> {
return listOf(
Triple(Potions.WATER, Ingredient.ofItems(CobblemonItems.MEDICINAL_LEEK), Potions.WATER), // This one is Mixin'd to result in brew rather than water
val recipes: List<Triple<CobblemonIngredient, CobblemonIngredient, Item>> by lazy {
listOf(
Triple(CobblemonPotionIngredient(Potions.WATER), CobblemonItemIngredient(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),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.SITRUS_BERRY, CobblemonItems.HYPER_POTION),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.LUM_BERRY, CobblemonItems.FULL_HEAL),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.PECHA_BERRY, CobblemonItems.ANTIDOTE),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.CHESTO_BERRY, CobblemonItems.AWAKENING),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.RAWST_BERRY, CobblemonItems.BURN_HEAL),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.ASPEAR_BERRY, CobblemonItems.ICE_HEAL),
convert(CobblemonItems.MEDICINAL_BREW, CobblemonItems.CHERI_BERRY, CobblemonItems.PARALYZE_HEAL),
convert(CobblemonItems.BURN_HEAL, CobblemonItems.LUM_BERRY, CobblemonItems.FULL_HEAL),
convert(CobblemonItems.ANTIDOTE, CobblemonItems.LUM_BERRY, CobblemonItems.FULL_HEAL),
convert(CobblemonItems.AWAKENING, CobblemonItems.LUM_BERRY, CobblemonItems.FULL_HEAL),
convert(CobblemonItems.ICE_HEAL, CobblemonItems.LUM_BERRY, CobblemonItems.FULL_HEAL),
convert(CobblemonItems.PARALYZE_HEAL, CobblemonItems.LUM_BERRY, CobblemonItems.FULL_HEAL),
convert(CobblemonItems.ETHER, CobblemonItems.PEP_UP_FLOWER, CobblemonItems.MAX_ETHER),
convert(CobblemonItems.ELIXIR, CobblemonItems.PEP_UP_FLOWER, CobblemonItems.MAX_ELIXIR),
convert(CobblemonItems.POTION, CobblemonItems.ENERGY_ROOT, CobblemonItems.SUPER_POTION),
convert(CobblemonItems.SUPER_POTION, CobblemonItems.FIGY_BERRY, CobblemonItems.HYPER_POTION),
convert(CobblemonItems.SUPER_POTION, CobblemonItems.WIKI_BERRY, CobblemonItems.HYPER_POTION),
convert(CobblemonItems.SUPER_POTION, CobblemonItems.MAGO_BERRY, CobblemonItems.HYPER_POTION),
convert(CobblemonItems.SUPER_POTION, CobblemonItems.AGUAV_BERRY, CobblemonItems.HYPER_POTION),
convert(CobblemonItems.SUPER_POTION, CobblemonItems.IAPAPA_BERRY, CobblemonItems.HYPER_POTION),
convert(CobblemonItems.HYPER_POTION, CobblemonItems.VIVICHOKE, CobblemonItems.MAX_POTION),
convert(CobblemonItems.MAX_POTION, CobblemonItems.LUM_BERRY, CobblemonItems.FULL_RESTORE)
)
}
fun getItemRecipes(): List<Triple<Item, Ingredient, Item>> {
// This is where the majority of our recipes go. First arg is thing down the bottom, second is thing up the top, third is results.
return listOf(
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.LEPPA_BERRY), CobblemonItems.ETHER),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.HOPO_BERRY), CobblemonItems.ELIXIR),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.ORAN_BERRY), CobblemonItems.POTION),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.SITRUS_BERRY), CobblemonItems.HYPER_POTION),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.LUM_BERRY), CobblemonItems.FULL_HEAL),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.PECHA_BERRY), CobblemonItems.ANTIDOTE),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.CHESTO_BERRY), CobblemonItems.AWAKENING),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.RAWST_BERRY), CobblemonItems.BURN_HEAL),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.ASPEAR_BERRY), CobblemonItems.ICE_HEAL),
Triple(CobblemonItems.MEDICINAL_BREW, Ingredient.ofItems(CobblemonItems.CHERI_BERRY), CobblemonItems.PARALYZE_HEAL),
Triple(CobblemonItems.BURN_HEAL, Ingredient.ofItems(CobblemonItems.LUM_BERRY), CobblemonItems.FULL_HEAL),
Triple(CobblemonItems.ANTIDOTE, Ingredient.ofItems(CobblemonItems.LUM_BERRY), CobblemonItems.FULL_HEAL),
Triple(CobblemonItems.AWAKENING, Ingredient.ofItems(CobblemonItems.LUM_BERRY), CobblemonItems.FULL_HEAL),
Triple(CobblemonItems.ICE_HEAL, Ingredient.ofItems(CobblemonItems.LUM_BERRY), CobblemonItems.FULL_HEAL),
Triple(CobblemonItems.PARALYZE_HEAL, Ingredient.ofItems(CobblemonItems.LUM_BERRY), CobblemonItems.FULL_HEAL),
Triple(CobblemonItems.ETHER, Ingredient.ofItems(CobblemonItems.PEP_UP_FLOWER), CobblemonItems.MAX_ETHER),
Triple(CobblemonItems.ELIXIR, Ingredient.ofItems(CobblemonItems.PEP_UP_FLOWER), CobblemonItems.MAX_ELIXIR),
Triple(CobblemonItems.POTION, Ingredient.ofItems(CobblemonItems.ENERGY_ROOT), CobblemonItems.SUPER_POTION),
Triple(CobblemonItems.SUPER_POTION, Ingredient.ofItems(CobblemonItems.FIGY_BERRY), CobblemonItems.HYPER_POTION),
Triple(CobblemonItems.SUPER_POTION, Ingredient.ofItems(CobblemonItems.WIKI_BERRY), CobblemonItems.HYPER_POTION),
Triple(CobblemonItems.SUPER_POTION, Ingredient.ofItems(CobblemonItems.MAGO_BERRY), CobblemonItems.HYPER_POTION),
Triple(CobblemonItems.SUPER_POTION, Ingredient.ofItems(CobblemonItems.AGUAV_BERRY), CobblemonItems.HYPER_POTION),
Triple(CobblemonItems.SUPER_POTION, Ingredient.ofItems(CobblemonItems.IAPAPA_BERRY), CobblemonItems.HYPER_POTION),
Triple(CobblemonItems.HYPER_POTION, Ingredient.ofItems(CobblemonItems.VIVICHOKE), CobblemonItems.MAX_POTION),
Triple(CobblemonItems.MAX_POTION, Ingredient.ofItems(CobblemonItems.LUM_BERRY), CobblemonItems.FULL_RESTORE)
)
private fun convert(input: Item, ingredient: Item, output: Item): Triple<CobblemonIngredient, CobblemonIngredient, Item> {
return Triple(CobblemonItemIngredient(input), CobblemonItemIngredient(ingredient), output)
}
}
@@ -0,0 +1,36 @@
/*
* 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.brewing.ingredient
import net.minecraft.item.ItemStack
import org.jetbrains.annotations.ApiStatus
/**
* The Cobblemon representation of a brewing ingredient.
* This is done to abstract platform specific requirements for a more custom solution to brewing.
*/
@ApiStatus.Internal
sealed interface CobblemonIngredient {
/**
* Tests if a given [stack] is valid for this ingredient.
*
* @param stack The [ItemStack] being tested.
* @return If the given [stack] is valid for this ingredient.
*/
fun matches(stack: ItemStack): Boolean
/**
* Resolves list of [ItemStack]s that is used by the vanilla Ingredient implementation when a platform requires wrapping.
*
* @return A list of [ItemStack]s
*/
fun matchingStacks(): List<ItemStack>
}
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.brewing.ingredient
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
class CobblemonItemIngredient(val item: Item) : CobblemonIngredient {
override fun matches(stack: ItemStack): Boolean = stack.isOf(this.item)
override fun matchingStacks(): List<ItemStack> = listOf(this.item.defaultStack)
}
@@ -0,0 +1,33 @@
/*
* 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.brewing.ingredient
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.potion.Potion
import net.minecraft.potion.PotionUtil
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
class CobblemonPotionIngredient(val potion: Potion) : CobblemonIngredient {
override fun matches(stack: ItemStack): Boolean {
val potion = PotionUtil.getPotion(stack)
return potion == this.potion
}
override fun matchingStacks(): List<ItemStack> {
val list = arrayListOf<ItemStack>()
list += PotionUtil.setPotion(Items.POTION.defaultStack, this.potion)
list += PotionUtil.setPotion(Items.SPLASH_POTION.defaultStack, this.potion)
list += PotionUtil.setPotion(Items.LINGERING_POTION.defaultStack, this.potion)
return list
}
}
@@ -18,28 +18,34 @@ import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
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.BerryModelRepository
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.pokeball.PokeBallRenderer
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController
import com.cobblemon.mod.common.client.starter.ClientPlayerData
import com.cobblemon.mod.common.client.storage.ClientStorageManager
import com.cobblemon.mod.common.client.trade.ClientTrade
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asTranslated
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.block.entity.HangingSignBlockEntityRenderer
import net.minecraft.client.render.block.entity.SignBlockEntityRenderer
import net.minecraft.client.render.entity.EntityRenderer
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.LivingEntityRenderer
import net.minecraft.client.render.entity.model.BoatEntityModel
import net.minecraft.client.render.entity.model.ChestBoatEntityModel
import net.minecraft.client.render.entity.model.PlayerEntityModel
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack
@@ -83,12 +89,11 @@ object CobblemonClient {
PlatformEvents.CLIENT_PLAYER_LOGIN.subscribe { onLogin() }
PlatformEvents.CLIENT_PLAYER_LOGOUT.subscribe { onLogout() }
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.HEALING_MACHINE, ::HealingMachineRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.BERRY, ::BerryBlockRenderer)
this.registerBlockEntityRenderers()
registerBlockRenderTypes()
//registerColors()
registerFlywheelRenderers()
this.registerEntityRenderers()
LOGGER.info("Registering custom BuiltinItemRenderers")
CobblemonBuiltinItemRendererRegistry.register(CobblemonItems.POKEMON_MODEL, PokemonItemRenderer())
@@ -96,6 +101,7 @@ object CobblemonClient {
PlatformEvents.CLIENT_ITEM_TOOLTIP.subscribe { event ->
val stack = event.stack
val lines = event.lines
val size = lines.size
@Suppress("DEPRECATION")
if (stack.item.registryEntry.key.isPresent && stack.item.registryEntry.key.get().value.namespace == Cobblemon.MODID) {
if (stack.nbt?.getBoolean(DataKeys.HIDE_TOOLTIP) == true) {
@@ -103,13 +109,14 @@ object CobblemonClient {
}
val language = Language.getInstance()
val key = this.baseLangKeyForItem(stack)
val offset = if (size > 1) 1 else 0
if (language.hasTranslation(key)) {
lines.add(key.asTranslated().gray())
lines.add(size - offset, key.asTranslated().gray())
}
var i = 1
var listKey = "${key}_$i"
while(language.hasTranslation(listKey)) {
lines.add(listKey.asTranslated().gray())
lines.add(size - offset, listKey.asTranslated().gray())
listKey = "${key}_${++i}"
}
}
@@ -143,6 +150,10 @@ object CobblemonClient {
RenderLayer.getCutout(),
CobblemonBlocks.APRICORN_DOOR,
CobblemonBlocks.APRICORN_TRAPDOOR,
CobblemonBlocks.APRICORN_SIGN,
CobblemonBlocks.APRICORN_WALL_SIGN,
CobblemonBlocks.APRICORN_HANGING_SIGN,
CobblemonBlocks.APRICORN_WALL_HANGING_SIGN,
CobblemonBlocks.BLACK_APRICORN_SAPLING,
CobblemonBlocks.BLUE_APRICORN_SAPLING,
CobblemonBlocks.GREEN_APRICORN_SAPLING,
@@ -176,6 +187,8 @@ object CobblemonClient {
CobblemonBlocks.REVIVAL_HERB,
*CobblemonBlocks.berries().values.toTypedArray()
)
this.createBoatModelLayers()
}
fun beforeChatRender(context: DrawContext, partialDeltaTicks: Float) {
@@ -194,14 +207,22 @@ object CobblemonClient {
renderer?.addFeature(PokemonOnShoulderRenderer(renderer))
}
fun registerPokemonRenderer(context: EntityRendererFactory.Context): PokemonRenderer {
LOGGER.info("Registering Pokémon renderer")
return PokemonRenderer(context)
private fun registerBlockEntityRenderers() {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.HEALING_MACHINE, ::HealingMachineRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.BERRY, ::BerryBlockRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.SIGN, ::SignBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.HANGING_SIGN, ::HangingSignBlockEntityRenderer)
}
fun registerPokeBallRenderer(context: EntityRendererFactory.Context): PokeBallRenderer {
private fun registerEntityRenderers() {
LOGGER.info("Registering Pokémon renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.POKEMON, ::PokemonRenderer)
LOGGER.info("Registering PokéBall renderer")
return PokeBallRenderer(context)
this.implementation.registerEntityRenderer(CobblemonEntities.EMPTY_POKEBALL, ::PokeBallRenderer)
LOGGER.info("Registering Boat renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.BOAT) { ctx -> CobblemonBoatRenderer(ctx, false) }
LOGGER.info("Registering Boat with Chest renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.CHEST_BOAT) { ctx -> CobblemonBoatRenderer(ctx, true) }
}
fun reloadCodedAssets(resourceManager: ResourceManager) {
@@ -215,11 +236,12 @@ object CobblemonClient {
PokeBallModelRepository.reload(resourceManager)
BerryModelRepository.reload(resourceManager)
LOGGER.info("Loaded assets")
// PokeBallModelRepository.reload(resourceManager)
}
fun endBattle() {
battle = null
battleOverlay.lastKnownBattle = null
BattleMusicController.endMusic()
}
private fun baseLangKeyForItem(stack: ItemStack): String {
@@ -230,4 +252,11 @@ object CobblemonClient {
return "${stack.translationKey}.tooltip"
}
private fun createBoatModelLayers() {
CobblemonBoatType.values().forEach { type ->
this.implementation.registerLayer(CobblemonBoatRenderer.createBoatModelLayer(type, false), BoatEntityModel::getTexturedModelData)
this.implementation.registerLayer(CobblemonBoatRenderer.createBoatModelLayer(type, true), ChestBoatEntityModel::getTexturedModelData)
}
}
}
@@ -57,6 +57,8 @@ fun drawProfilePokemon(
val context = RenderContext()
PokemonModelRepository.getTextureNoSubstitute(species, aspects, 0f).let { it -> context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, PokemonSpecies.getByIdentifier(species)!!.getForm(aspects).baseScale)
context.put(RenderContext.SPECIES, species)
context.put(RenderContext.ASPECTS, aspects)
val renderType = model.getLayer(texture)
@@ -13,12 +13,14 @@ import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.ClientBattleActor
import com.cobblemon.mod.common.client.battle.SingleActionRequest
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleActionSelection
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleBackButton
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleGeneralActionSelection
import com.cobblemon.mod.common.client.gui.battle.subscreen.BattleSwitchPokemonSelection
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleMessagePane
import com.cobblemon.mod.common.client.keybind.boundKey
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.MinecraftClient
@@ -41,6 +43,7 @@ class BattleGUI : Screen(battleLang("gui.title")) {
private lateinit var messagePane: BattleMessagePane
var opacity = 0F
val actor = CobblemonClient.battle?.side1?.actors?.find { it.uuid == MinecraftClient.getInstance().player?.uuid }
val specBackButton = BattleBackButton(12f, MinecraftClient.getInstance().window.scaledHeight - 32f)
var queuedActions = mutableListOf<() -> Unit>()
@@ -106,6 +109,10 @@ class BattleGUI : Screen(battleLang("gui.title")) {
}
}
if (battle.spectating) {
specBackButton.render(context.matrices, mouseX, mouseY, delta)
}
val currentSelection = getCurrentActionSelection()
if (currentSelection == null || currentSelection is BattleGeneralActionSelection ) {
drawScaledText(
@@ -153,4 +160,13 @@ class BattleGUI : Screen(battleLang("gui.title")) {
}
return super.charTyped(chr, modifiers)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
val battle = CobblemonClient.battle
if (battle?.spectating == true && specBackButton.isHovered(mouseX, mouseY)) {
RemoveSpectatorPacket(battle.battleId).sendToServer()
CobblemonClient.endBattle()
}
return super.mouseClicked(mouseX, mouseY, button)
}
}
@@ -9,8 +9,7 @@
package com.cobblemon.mod.common.client.gui.battle.subscreen
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.battles.ShowdownPokemon
import com.cobblemon.mod.common.battles.SwitchActionResponse
import com.cobblemon.mod.common.battles.*
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.SingleActionRequest
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
@@ -24,6 +23,7 @@ import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.sound.SoundManager
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.math.MathHelper.ceil
class BattleSwitchPokemonSelection(
battleGUI: BattleGUI,
@@ -83,7 +83,6 @@ class BattleSwitchPokemonSelection(
partialTicks = deltaTicks
)
} catch (exception: Exception) {
println(showdownPokemon.condition)
throw exception
}
}
@@ -98,9 +97,15 @@ class BattleSwitchPokemonSelection(
.find { it.uuid == showdownPokemon.uuid }
?.let { showdownPokemon to it }
}
.filter {
if (request.side.pokemon[0].reviving) {
"fnt" in it.first.condition
} else {
"fnt" !in it.first.condition
}
}
.filter { it.second.uuid !in battleGUI.actor!!.activePokemon.map { it.battlePokemon?.uuid } }
.filter { it.second.uuid !in switchingInPokemon }
.filter { "fnt" !in it.first.condition || it.first.reviving }
showdownPokemonToPokemon.forEachIndexed { index, (showdownPokemon, pokemon) ->
val row = index / 2
@@ -10,7 +10,9 @@ package com.cobblemon.mod.common.client.gui.interact.wheel
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
@@ -48,14 +50,14 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean): Intera
return InteractWheelGUI(options, Text.translatable("cobblemon.ui.interact.pokemon"))
}
fun createPlayerInteractGui(targetPlayer: PlayerEntity, pokemon: Pokemon): InteractWheelGUI {
fun createPlayerInteractGui(optionsPacket: PlayerInteractOptionsPacket): InteractWheelGUI {
val trade = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/icon_trade.png"),
colour = { if (CobblemonClient.requests.tradeOffers.any { it.traderId == targetPlayer.uuid }) Vector3f(0F, 0.6F, 0F) else null },
colour = { if (CobblemonClient.requests.tradeOffers.any { it.traderId == optionsPacket.targetId }) Vector3f(0F, 0.6F, 0F) else null },
onPress = {
val tradeOffer = CobblemonClient.requests.tradeOffers.find { it.traderId == targetPlayer.uuid }
val tradeOffer = CobblemonClient.requests.tradeOffers.find { it.traderId == optionsPacket.targetId }
if (tradeOffer == null) {
CobblemonNetwork.sendToServer(OfferTradePacket(targetPlayer.uuid))
CobblemonNetwork.sendToServer(OfferTradePacket(optionsPacket.targetId))
} else {
CobblemonClient.requests.tradeOffers -= tradeOffer
CobblemonNetwork.sendToServer(AcceptTradeRequestPacket(tradeOffer.tradeOfferId))
@@ -65,18 +67,35 @@ fun createPlayerInteractGui(targetPlayer: PlayerEntity, pokemon: Pokemon): Inter
)
val battle = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/icon_battle.png"),
colour = { if (CobblemonClient.requests.battleChallenges.any { it.challengerId == targetPlayer.uuid }) Vector3f(0F, 0.6F, 0F) else null },
colour = { if (CobblemonClient.requests.battleChallenges.any { it.challengerId == optionsPacket.targetId }) Vector3f(0F, 0.6F, 0F) else null },
onPress = {
val battleRequest = CobblemonClient.requests.battleChallenges.find { it.challengerId == targetPlayer.uuid }
val battleRequest = CobblemonClient.requests.battleChallenges.find { it.challengerId == optionsPacket.targetId }
// This can be improved in future with more detailed battle challenge data.
BattleChallengePacket(targetPlayer.id, pokemon.uuid).sendToServer()
BattleChallengePacket(optionsPacket.numericTargetId, optionsPacket.selectedPokemonId).sendToServer()
closeGUI()
}
)
val options = mutableMapOf(
Orientation.TOP_LEFT to trade,
Orientation.TOP_RIGHT to battle
val spectate = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/icon_spectate_battle.png"),
colour = { if (CobblemonClient.requests.battleChallenges.any { it.challengerId == optionsPacket.targetId }) Vector3f(0F, 0.6F, 0F) else null },
onPress = {
SpectateBattlePacket(optionsPacket.targetId).sendToServer()
closeGUI()
}
)
val options = mutableMapOf<Orientation, InteractWheelOption>()
//The way things are positioned should probably be more thought out if more options are added
optionsPacket.options.map {
if (it.equals(PlayerInteractOptionsPacket.Options.TRADE)) {
options[Orientation.TOP_LEFT] = trade
}
if (it.equals(PlayerInteractOptionsPacket.Options.BATTLE)) {
options[Orientation.TOP_RIGHT] = battle
}
if (it.equals(PlayerInteractOptionsPacket.Options.SPECTATE_BATTLE)) {
options[Orientation.TOP_RIGHT] = spectate
}
}
return InteractWheelGUI(options, Text.translatable("cobblemon.ui.interact.player"))
}
@@ -11,15 +11,14 @@ package com.cobblemon.mod.common.client.keybind.keybinds
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToServer
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.gui.interact.wheel.createPlayerInteractGui
import com.cobblemon.mod.common.client.keybind.CobblemonBlockingKeyBinding
import com.cobblemon.mod.common.client.keybind.KeybindCategories
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.traceFirstEntityCollision
import javax.swing.plaf.basic.BasicSliderUI.ScrollListener
import net.minecraft.client.MinecraftClient
import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.util.InputUtil
@@ -90,7 +89,9 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
private fun processEntityTarget(player: ClientPlayerEntity, pokemon: Pokemon, entity: LivingEntity) {
when (entity) {
is PlayerEntity -> {
MinecraftClient.getInstance().setScreen(createPlayerInteractGui(entity, pokemon))
//This sends a packet to the server with the id of the player
//The server sends a packet back that opens the player interaction menu with the proper options
sendPacketToServer(RequestPlayerInteractionsPacket(entity.uuid, entity.id, pokemon.uuid))
}
is PokemonEntity -> {
if (!entity.canBattle(player)) return
@@ -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.net
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.client.gui.interact.wheel.createPlayerInteractGui
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import net.minecraft.client.MinecraftClient
object PlayerInteractOptionsHandler : ClientNetworkPacketHandler<PlayerInteractOptionsPacket> {
override fun handle(packet: PlayerInteractOptionsPacket, client: MinecraftClient) {
MinecraftClient.getInstance().setScreen(createPlayerInteractGui(packet))
}
}
@@ -32,10 +32,10 @@ object BattleInitializeHandler : ClientNetworkPacketHandler<BattleInitializePack
}
val otherSide = if (mySide == packet.side1) packet.side2 else packet.side1
side1.actors.addAll(mySide.actors.map{ actorFromDTO(it, true) })
val sides = listOf(packet.side1, packet.side2)
spectating = !sides.any { it.actors.any { it.uuid == MinecraftClient.getInstance().player?.uuid } }
side1.actors.addAll(mySide.actors.map{ actorFromDTO(it, !spectating) })
side2.actors.addAll(otherSide.actors.map{ actorFromDTO(it, false) })
spectating = sides.any { it.actors.any { it.uuid == MinecraftClient.getInstance().player?.uuid } }
for (side in listOf(side1, side2)) {
side.battle = this
for (actor in side.actors) {
@@ -9,101 +9,33 @@
package com.cobblemon.mod.common.client.net.battle
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.access.SoundManagerDuck
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.mixin.accessor.MusicTrackerAccessor
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController
import com.cobblemon.mod.common.client.sound.battle.BattleMusicInstance
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
import net.minecraft.client.MinecraftClient
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.sound.SoundInstance
import net.minecraft.client.sound.SoundManager
import net.minecraft.client.sound.TickableSoundInstance
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvent
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.MathHelper
/**
* The handler for [BattleMusicPacket]s. Interfaces with [BattleMusicController] to change battle music.
*
* @author Segfault Guy
* @since April 22nd, 2023
*/
object BattleMusicHandler : ClientNetworkPacketHandler<BattleMusicPacket> {
// Keep a reference for look-up in SoundManager
var music: BattleMusicInstance? = null
// SoundCategories that are blocked while battle music is playing
private val interferences = listOf(SoundCategory.AMBIENT, SoundCategory.RECORDS)
override fun handle(packet: BattleMusicPacket, client: MinecraftClient) {
val soundManager = client.soundManager
val newMusic = packet.music
val currMusic = this.music
val newMusic = packet.music?.let { BattleMusicInstance(it, packet.volume, packet.pitch) }
val currMusic = BattleMusicController.music
if (newMusic == null)
soundManager.endMusic()
else if (currMusic == null)
soundManager.initializeMusic(newMusic, packet.volume, packet.pitch)
BattleMusicController.endMusic()
else if (!soundManager.isPlaying(currMusic))
BattleMusicController.initializeMusic(newMusic)
else if (newMusic.id != currMusic.id)
soundManager.switchMusic(newMusic, packet.volume, packet.pitch)
BattleMusicController.switchMusic(newMusic)
else
LOGGER.error("Ignored BattleMusicPacket from server: ${packet.music?.id}")
}
// stop all interference sounds currently playing and start a new BattleMusicInstance
private fun SoundManager.initializeMusic(sound: SoundEvent, volume: Float, pitch: Float) {
this.stopSounds(null, SoundCategory.MUSIC)
interferences.forEach { this.stopSounds(null, it) }
(this as SoundManagerDuck).toggleCategories(*interferences.toTypedArray())
music = BattleMusicInstance(sound, volume, pitch)
this.play(music)
}
// switch (without fade) to a new BattleMusicInstance if one is already playing
private fun SoundManager.switchMusic(sound: SoundEvent, volume: Float, pitch: Float) {
this.stop(music)
music = BattleMusicInstance(sound, volume, pitch)
this.play(music)
}
// fade out and end current BattleMusicInstance
private fun SoundManager.endMusic() {
(this as SoundManagerDuck).toggleCategories(*interferences.toTypedArray())
music?.setFade()
music = null
}
}
class BattleMusicInstance(sound: SoundEvent, volume: Float, pitch: Float) :
PositionedSoundInstance(sound, SoundCategory.MUSIC, volume, pitch, SoundInstance.createRandom(), BlockPos.ORIGIN), TickableSoundInstance {
private var fade: Boolean = false
private var done: Boolean = false
private val tracker: MusicTrackerAccessor
private var tickCount = 0
private var fadeCount = 0
private val fadeTime = 60.0
private var initVolume = 1.0
init {
this.relative = true
this.repeat = true
this.attenuationType = SoundInstance.AttenuationType.NONE
this.tracker = MinecraftClient.getInstance().musicTracker as MusicTrackerAccessor
this.initVolume = volume.toDouble()
}
override fun isDone(): Boolean {
return this.done
}
fun setFade() {
this.fade = true
this.repeat = false
}
override fun tick() {
++tickCount
if (fade) {
++fadeCount
this.volume = MathHelper.lerp(fadeCount/fadeTime, initVolume, 0.0).toFloat()
if (volume <= 0) this.done = true
}
if (tickCount % 20 == 0) tracker.setTimeUntilNextSong(tracker.timeUntilNextSong() + 20)
}
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.client.net.effect
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
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
@@ -23,10 +24,11 @@ object SpawnSnowstormParticleHandler : ClientNetworkPacketHandler<SpawnSnowstorm
val wrapper = MatrixWrapper()
val matrix = MatrixStack()
matrix.translate(packet.position.x, packet.position.y, packet.position.z)
matrix.multiply(POSITIVE_Y.rotationDegrees(packet.yawDegrees))
matrix.multiply(NEGATIVE_X.rotationDegrees(packet.pitchDegrees))
// matrix.multiply(POSITIVE_Y.rotationDegrees(packet.yawDegrees))
// matrix.multiply(NEGATIVE_X.rotationDegrees(packet.pitchDegrees))
wrapper.updateMatrix(matrix.peek().positionMatrix)
val world = MinecraftClient.getInstance().world ?: return
ParticleStorm(packet.effect, wrapper, world).spawn()
val effect = BedrockParticleEffectRepository.getEffect(packet.effectId) ?: return
ParticleStorm(effect, wrapper, world).spawn()
}
}
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.boat
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.entity.EntityRenderer
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.model.BoatEntityModel
import net.minecraft.client.render.entity.model.ChestBoatEntityModel
import net.minecraft.client.render.entity.model.EntityModelLayer
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.RotationAxis
import org.joml.Quaternionf
class CobblemonBoatRenderer(ctx: EntityRendererFactory.Context, private val hasChest: Boolean) : EntityRenderer<CobblemonBoatEntity>(ctx) {
private val boatModels = hashMapOf<CobblemonBoatType, Pair<Identifier, BoatEntityModel>>()
init {
this.shadowRadius = 0.8F
CobblemonBoatType.values().forEach { type ->
this.boatModels[type] = generateTextureIdentifier(type, this.hasChest) to generateBoatModel(ctx, type, this.hasChest)
}
}
override fun getTexture(entity: CobblemonBoatEntity): Identifier = this.boatModels[entity.boatType]!!.first
override fun render(entity: CobblemonBoatEntity, yaw: Float, tickDelta: Float, matrices: MatrixStack, vertexConsumers: VertexConsumerProvider, light: Int) {
matrices.push()
matrices.translate(0F, 0.375F, 0F)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180F - yaw))
val h = entity.damageWobbleTicks - tickDelta
val j = (entity.damageWobbleStrength - tickDelta).coerceAtLeast(0F)
if (h > 0F) {
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(MathHelper.sin(h) * h * j / 10F * entity.damageWobbleSide))
}
val k = entity.interpolateBubbleWobble(tickDelta)
if (!MathHelper.approximatelyEquals(k, 0F)) {
matrices.multiply(Quaternionf().setAngleAxis(entity.interpolateBubbleWobble(tickDelta) * 0.017453292F, 1F, 0F, 1F))
}
val (identifier, entityModel) = this.boatModels[entity.boatType]!!
matrices.scale(-1F, -1F, 1F)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(90F))
entityModel.setAngles(entity, tickDelta, 0F, -0.1F, 0F, 0F)
val vertexConsumer = vertexConsumers.getBuffer(entityModel.getLayer(identifier))
entityModel.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, 1F, 1F, 1F, 1F)
if (!entity.isSubmergedInWater) {
val vertexConsumer2 = vertexConsumers.getBuffer(RenderLayer.getWaterMask())
entityModel.waterPatch.render(matrices, vertexConsumer2, light, OverlayTexture.DEFAULT_UV)
}
matrices.pop()
super.render(entity, yaw, tickDelta, matrices, vertexConsumers, light)
}
companion object {
private fun generateTextureIdentifier(type: CobblemonBoatType, hasChest: Boolean): Identifier {
val boatSubPath = if (hasChest) "chest_boat" else "boat"
val path = "textures/entity/$boatSubPath/${type.name.lowercase()}.png"
return cobblemonResource(path)
}
private fun generateBoatModel(ctx: EntityRendererFactory.Context, type: CobblemonBoatType, hasChest: Boolean): BoatEntityModel {
val modelLayer = this.createBoatModelLayer(type, hasChest)
val modelPart = ctx.getPart(modelLayer)
return if (hasChest) ChestBoatEntityModel(modelPart) else BoatEntityModel(modelPart)
}
internal fun createBoatModelLayer(type: CobblemonBoatType, hasChest: Boolean): EntityModelLayer {
val boatSubPath = if (hasChest) "chest_boat" else "boat"
val path = "$boatSubPath/${type.name.lowercase()}"
return EntityModelLayer(cobblemonResource(path), "main")
}
}
}
@@ -69,7 +69,7 @@ class PokemonOnShoulderRenderer<T : PlayerEntity>(renderLayerParent: FeatureRend
matrixStack.push()
val uuid = this.extractUuid(compoundTag)
val cache = this.playerCache.getOrPut(livingEntity.uuid) { ShoulderCache() }
val shoulderData: ShoulderData
var shoulderData: ShoulderData? = null
if (pLeftShoulder && cache.lastKnownLeft?.uuid != uuid) {
shoulderData = this.extractData(compoundTag, uuid)
cache.lastKnownLeft = shoulderData
@@ -78,8 +78,9 @@ class PokemonOnShoulderRenderer<T : PlayerEntity>(renderLayerParent: FeatureRend
shoulderData = this.extractData(compoundTag, uuid)
cache.lastKnownRight = shoulderData
}
else {
// should never be null but might as well be safe
if (shoulderData == null){
// Could be null
shoulderData = (if (pLeftShoulder) cache.lastKnownLeft else cache.lastKnownRight) ?: return
}
val scale = shoulderData.form.baseScale * shoulderData.scaleModifier
@@ -136,13 +137,15 @@ class PokemonOnShoulderRenderer<T : PlayerEntity>(renderLayerParent: FeatureRend
return shoulderNbt.getUuid(DataKeys.SHOULDER_UUID)
}
private fun extractData(shoulderNbt: NbtCompound, pokemonUUID: UUID): ShoulderData {
private fun extractData(shoulderNbt: NbtCompound, pokemonUUID: UUID): ShoulderData? {
// To not crash with existing ones, this will still have the aspect issue
if (!shoulderNbt.contains(DataKeys.SHOULDER_SPECIES)) {
val pokemon = Pokemon().apply { isClient = true }.loadFromNBT(shoulderNbt.getCompound(DataKeys.POKEMON))
return ShoulderData(pokemonUUID, pokemon.species, pokemon.form, pokemon.aspects, pokemon.scaleModifier)
}
val species = PokemonSpecies.getByIdentifier(Identifier(shoulderNbt.getString(DataKeys.SHOULDER_SPECIES)))!!
val species = PokemonSpecies.getByIdentifier(Identifier(shoulderNbt.getString(DataKeys.SHOULDER_SPECIES)))
?: return null
val formName = shoulderNbt.getString(DataKeys.SHOULDER_FORM)
val form = species.forms.firstOrNull { it.name == formName } ?: species.standardForm
val aspects = shoulderNbt.getList(DataKeys.SHOULDER_ASPECTS, NbtElement.STRING_TYPE.toInt()).map { it.asString() }.toSet()
@@ -19,7 +19,7 @@ import net.minecraft.client.model.ModelPart
class PokeBallModel(root: ModelPart) : PoseableEntityModel<EmptyPokeBallEntity>(), PokeBallFrame {
override val rootPart = root.registerChildWithAllChildren("poke_ball")
override val base = getPart("base")
override val base = getPart("bottom")
override val lid = getPart("lid")
override val isForLivingEntityRenderer = false
@@ -97,6 +97,8 @@ abstract class PokemonPoseableModel : PoseableEntityModel<PokemonEntity>() {
override fun setupEntityTypeContext(entity: PokemonEntity?) {
entity?.let {
context.put(RenderContext.SCALE, it.pokemon.form.baseScale)
context.put(RenderContext.SPECIES, it.pokemon.species.resourceIdentifier)
context.put(RenderContext.ASPECTS, it.pokemon.aspects)
PokemonModelRepository.getTexture(it.pokemon.species.resourceIdentifier, it.pokemon.aspects, 0f).let { texture -> context.put(RenderContext.TEXTURE, texture) }
}
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.asTransformed
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart
@@ -23,44 +24,50 @@ import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class GolbatModel(root: ModelPart) : PokemonPoseableModel(), BiWingedFrame {
class GolbatModel(root: ModelPart) : PokemonPoseableModel() {
override val rootPart = root.registerChildWithAllChildren("golbat")
override val leftWing = getPart("leftwing")
override val rightWing = getPart("rightwing")
override val portraitScale = 1.55F
override val portraitTranslation = Vec3d(0.0, -0.55, 0.0)
override val portraitTranslation = Vec3d(-0.1, -0.1, 0.0)
override val profileScale = 0.9F
override val profileTranslation = Vec3d(0.0, 0.4, 0.0)
override val profileScale = 0.7F
override val profileTranslation = Vec3d(0.0, 0.7, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var hover: PokemonPose
lateinit var fly: PokemonPose
lateinit var battleidle: PokemonPose
// override val cryAnimation = CryProvider { _, _ -> bedrockStateful("golbat", "cry").setPreventsIdle(false) }
override fun registerPoses() {
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES - PoseType.HOVER,
transformTicks = 10,
idleAnimations = arrayOf(
//bedrock("golbat", "ground_idle")
)
)
val blink = quirk("blink") { bedrockStateful("golbat", "blink").setPreventsIdle(false) }
sleep = registerPose(
poseType = PoseType.SLEEP,
idleAnimations = arrayOf(bedrock("golbat", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES - PoseType.HOVER,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
idleAnimations = arrayOf(
bedrock("golbat", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES - PoseType.FLY,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
//bedrock("golbat", "ground_walk")
bedrock("golbat", "ground_walk")
)
)
@@ -68,12 +75,9 @@ class GolbatModel(root: ModelPart) : PokemonPoseableModel(), BiWingedFrame {
poseName = "hover",
poseType = PoseType.HOVER,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
WingFlapIdleAnimation(this,
flapFunction = sineFunction(verticalShift = -10F.toRadians(), period = 0.9F, amplitude = 0.6F),
timeVariable = { state, _, _ -> state?.animationSeconds ?: 0F },
axis = TransformedModelPart.Y_AXIS
)
bedrock("golbat", "air_idle")
)
)
@@ -81,12 +85,20 @@ class GolbatModel(root: ModelPart) : PokemonPoseableModel(), BiWingedFrame {
poseName = "fly",
poseType = PoseType.FLY,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
WingFlapIdleAnimation(this,
flapFunction = sineFunction(verticalShift = -14F.toRadians(), period = 0.9F, amplitude = 0.9F),
timeVariable = { state, _, _ -> state?.animationSeconds ?: 0F },
axis = TransformedModelPart.Y_AXIS
)
bedrock("golbat", "air_fly")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
idleAnimations = arrayOf(
bedrock("golbat", "battle_idle")
)
)
}
@@ -23,14 +23,14 @@ class GolemModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFr
override val rootPart = root.registerChildWithAllChildren("golem")
override val head = getPart("head")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val leftLeg = getPart("left_upper_leg")
override val rightLeg = getPart("right_upper_leg")
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(-0.55, -0.55, 0.0)
override val portraitScale = 1.7F
override val portraitTranslation = Vec3d(-0.6, -0.25, 0.0)
override val profileScale = 0.88F
override val profileTranslation = Vec3d(0.0, 0.42, 0.0)
override val profileScale = 0.75F
override val profileTranslation = Vec3d(0.0, 0.55, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
@@ -43,7 +43,7 @@ class GolemModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFr
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("golem", "ground_idle")
bedrock("golem", "test")
)
)
@@ -54,7 +54,7 @@ class GolemModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFr
idleAnimations = arrayOf(
BipedWalkAnimation(this, periodMultiplier = 1.2F, amplitudeMultiplier = 0.9f),
singleBoneLook(),
bedrock("golem", "ground_idle")
bedrock("golem", "test")
//bedrock("golem", "ground_walk")
)
)
@@ -37,7 +37,6 @@ class KadabraModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Biped
override val profileScale = 0.75F
override val profileTranslation = Vec3d(0.0, 0.6, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var battleidle: PokemonPose
@@ -10,11 +10,14 @@ package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.EarJoint
import com.cobblemon.mod.common.client.render.models.blockbench.RangeOfMotion
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.asTransformed
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.EaredFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart.Companion.X_AXIS
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart.Companion.Y_AXIS
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart.Companion.Z_AXIS
@@ -27,81 +30,121 @@ import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.MathConstants.PI
import net.minecraft.util.math.Vec3d
class ZubatModel(root: ModelPart) : PokemonPoseableModel(), BiWingedFrame, EaredFrame {
class ZubatModel(root: ModelPart) : PokemonPoseableModel() {
override val rootPart = root.registerChildWithAllChildren("zubat")
override val leftWing = getPart("leftwing")
override val rightWing = getPart("rightwing")
val wings_folded = getPart("wings_folded")
val wings_open = getPart("wings_open")
private val leftEar = getPart("leftear")
private val rightEar = getPart("rightear")
override val leftEarJoint = EarJoint(leftEar, Z_AXIS, RangeOfMotion(70F.toRadians(), 40F.toRadians()))
override val rightEarJoint = EarJoint(rightEar, Z_AXIS, RangeOfMotion((-70F).toRadians(), (-40F).toRadians()))
override val portraitScale = 1.7F
override val portraitTranslation = Vec3d(0.0, 0.0, 0.0)
override val portraitScale = 2.3F
override val portraitTranslation = Vec3d(0.0, -0.5, 0.0)
override val profileScale = 1.0F
override val profileTranslation = Vec3d(0.0, 0.36, 0.0)
override val profileScale = 0.7F
override val profileTranslation = Vec3d(0.0, 0.7, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var hover: PokemonPose
lateinit var fly: PokemonPose
lateinit var shoulderLeft: PokemonPose
lateinit var shoulderRight: PokemonPose
val shoulderOffset = 0
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("zubat", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val twitch = quirk("twitch") { bedrockStateful("zubat", "eartwitch").setPreventsIdle(false) }
sleep = registerPose(
poseType = PoseType.SLEEP,
transformedParts = arrayOf(
wings_folded.asTransformed().withVisibility(visibility = false),
wings_open.asTransformed().withVisibility(visibility = true),
),
quirks = arrayOf(twitch),
idleAnimations = arrayOf(bedrock("zubat", "sleep"))
)
registerPose(
poseName = "hover",
poseTypes = ALL_POSES - SHOULDER_POSES - PoseType.FLY - PoseType.SLEEP,
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES - PoseType.HOVER,
transformedParts = arrayOf(
wings_folded.asTransformed().withVisibility(visibility = false),
wings_open.asTransformed().withVisibility(visibility = true),
),
transformTicks = 10,
quirks = arrayOf(twitch),
idleAnimations = arrayOf(
bedrock("zubat", "ground_idle")
)
)
registerPose(
poseName = "fly",
poseType = PoseType.FLY,
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES - PoseType.FLY,
transformedParts = arrayOf(
wings_folded.asTransformed().withVisibility(visibility = false),
wings_open.asTransformed().withVisibility(visibility = true),
),
transformTicks = 10,
quirks = arrayOf(twitch),
idleAnimations = arrayOf(
bedrock("zubat", "ground_walk")
)
)
registerPose(
poseType = PoseType.SHOULDER_LEFT,
idleAnimations = arrayOf(
leftWing.rotation(
function = sineFunction(
amplitude = PI / 3,
period = 1F
),
axis = Z_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
)
),
hover = registerPose(
poseName = "hover",
poseType = PoseType.HOVER,
transformedParts = arrayOf(
rootPart.asTransformed().addRotation(X_AXIS, PI / 9).addPosition(Y_AXIS, 4F).addPosition(Z_AXIS, 3F),
leftWing.asTransformed().addRotation(X_AXIS, PI / 3),
rightWing.asTransformed().addRotation(X_AXIS, PI / 3).addRotation(Z_AXIS, -PI / 2)
wings_folded.asTransformed().withVisibility(visibility = false),
wings_open.asTransformed().withVisibility(visibility = true),
),
transformTicks = 10,
quirks = arrayOf(twitch),
idleAnimations = arrayOf(
bedrock("zubat", "air_idle")
)
)
registerPose(
poseType = PoseType.SHOULDER_RIGHT,
fly = registerPose(
poseName = "fly",
poseType = PoseType.FLY,
transformedParts = arrayOf(
wings_folded.asTransformed().withVisibility(visibility = false),
wings_open.asTransformed().withVisibility(visibility = true),
),
quirks = arrayOf(twitch),
transformTicks = 10,
idleAnimations = arrayOf(
rightWing.rotation(
function = sineFunction(
amplitude = PI / 3,
period = 1F
),
axis = Z_AXIS,
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
)
bedrock("zubat", "air_fly")
)
)
shoulderLeft = registerPose(
poseType = PoseType.SHOULDER_LEFT,
idleAnimations = arrayOf(
bedrock("zubat", "shoulder_left")
),
transformedParts = arrayOf(
rootPart.asTransformed().addRotation(X_AXIS, PI / 9).addPosition(Y_AXIS, 4F).addPosition(Z_AXIS, 3F),
leftWing.asTransformed().addRotation(X_AXIS, PI / 3).addRotation(Z_AXIS, PI / 2),
rightWing.asTransformed().addRotation(X_AXIS, PI / 3)
rootPart.asTransformed().addPosition(TransformedModelPart.X_AXIS, shoulderOffset)
)
)
shoulderRight = registerPose(
poseType = PoseType.SHOULDER_RIGHT,
idleAnimations = arrayOf(
bedrock("zubat", "shoulder_right")
),
transformedParts = arrayOf(
rootPart.asTransformed().addPosition(TransformedModelPart.X_AXIS, -shoulderOffset)
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("zubat", "faint") else null
}
@@ -10,6 +10,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.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart
@@ -19,26 +20,37 @@ import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class CrobatModel(root: ModelPart) : PokemonPoseableModel(), BiWingedFrame {
class CrobatModel(root: ModelPart) : PokemonPoseableModel() {
override val rootPart = root.registerChildWithAllChildren("crobat")
override val leftWing = getPart("leftwings")
override val rightWing = getPart("rightwings")
override val portraitScale = 1.8F
override val portraitTranslation = Vec3d(-0.11, -0.77, 0.0)
override val portraitScale = 1.2F
override val portraitTranslation = Vec3d(-0.1, 1.8, 0.0)
override val profileScale = 0.9F
override val profileTranslation = Vec3d(0.0, 0.35, 0.0)
override val profileScale = 0.5F
override val profileTranslation = Vec3d(0.0, 1.2, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var hover: PokemonPose
lateinit var fly: PokemonPose
lateinit var walk: PokemonPose
lateinit var battleidle: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("crobat", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("crobat", "blink").setPreventsIdle(false) }
sleep = registerPose(
poseType = PoseType.SLEEP,
idleAnimations = arrayOf(bedrock("crobat", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseType = PoseType.STAND,
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES - PoseType.HOVER,
condition = { !it.isBattling },
transformTicks = 10,
idleAnimations = arrayOf(
bedrock("crobat", "ground_idle")
)
@@ -57,13 +69,9 @@ class CrobatModel(root: ModelPart) : PokemonPoseableModel(), BiWingedFrame {
poseName = "hover",
poseType = PoseType.HOVER,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("crobat", "ground_idle"),
WingFlapIdleAnimation(this,
flapFunction = sineFunction(verticalShift = -10F.toRadians(), period = 0.9F, amplitude = 0.6F),
timeVariable = { state, _, _ -> state?.animationSeconds ?: 0F },
axis = TransformedModelPart.Y_AXIS
)
bedrock("crobat", "air_idle")
)
)
@@ -71,13 +79,20 @@ class CrobatModel(root: ModelPart) : PokemonPoseableModel(), BiWingedFrame {
poseName = "fly",
poseType = PoseType.FLY,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("crobat", "ground_walk"),
WingFlapIdleAnimation(this,
flapFunction = sineFunction(verticalShift = -14F.toRadians(), period = 0.9F, amplitude = 0.9F),
timeVariable = { state, _, _ -> state?.animationSeconds ?: 0F },
axis = TransformedModelPart.Y_AXIS
)
bedrock("crobat", "air_fly")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
idleAnimations = arrayOf(
bedrock("crobat", "battle_idle")
)
)
}
@@ -8,42 +8,53 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.asTransformed
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class HitmontopModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame, BimanualFrame {
class HitmontopModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("hitmontop")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val portraitScale = 2.6F
override val portraitTranslation = Vec3d(-0.26, -0.5, 0.0)
override val profileScale = 0.91F
override val profileTranslation = Vec3d(0.0, 0.4, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var battleidle: PokemonPose
// override val cryAnimation = CryProvider { _, _ -> bedrockStateful("hitmontop", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("hitmontop", "blink").setPreventsIdle(false)}
val blink = quirk("blink") { bedrockStateful("hitmontop", "blink").setPreventsIdle(false) }
sleep = registerPose(
poseType = PoseType.SLEEP,
idleAnimations = arrayOf(bedrock("hitmontop", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
condition = { !it.isBattling },
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
@@ -53,19 +64,29 @@ class HitmontopModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("hitmontop", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
bedrock("hitmontop", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("hitmontop", "battle_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("hitmontop", "faint") else null
override fun getFaintAnimation(
pokemonEntity: PokemonEntity,
state: PoseableEntityState<PokemonEntity>
) = bedrockStateful("hitmontop", "faint")
}
@@ -8,42 +8,59 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.asTransformed
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class TyrogueModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame, BimanualFrame {
class TyrogueModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("tyrogue")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val portraitScale = 2.56F
override val portraitTranslation = Vec3d(-0.24, 0.1, 0.0)
override val profileScale = 0.73F
override val profileTranslation = Vec3d(-0.03, 0.7, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var shoulderLeft: PokemonPose
lateinit var shoulderRight: PokemonPose
lateinit var battleidle: PokemonPose
val shoulderOffset = 3
// override val cryAnimation = CryProvider { _, _ -> bedrockStateful("tyrogue", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("tyrogue", "blink").setPreventsIdle(false)}
val blink = quirk("blink") { bedrockStateful("tyrogue", "blink").setPreventsIdle(false) }
sleep = registerPose(
poseType = PoseType.SLEEP,
idleAnimations = arrayOf(bedrock("tyrogue", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
condition = { !it.isBattling },
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
@@ -53,19 +70,55 @@ class TyrogueModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Biped
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("tyrogue", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
bedrock("tyrogue", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("tyrogue", "battle_idle")
)
)
shoulderLeft = registerPose(
poseType = PoseType.SHOULDER_LEFT,
quirks = arrayOf(blink),
condition = { !it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("tyrogue", "shoulder_left")
),
transformedParts = arrayOf(
rootPart.asTransformed().addPosition(TransformedModelPart.X_AXIS, shoulderOffset)
)
)
shoulderRight = registerPose(
poseType = PoseType.SHOULDER_RIGHT,
quirks = arrayOf(blink),
condition = { !it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("tyrogue", "shoulder_right")
),
transformedParts = arrayOf(
rootPart.asTransformed().addPosition(TransformedModelPart.X_AXIS, -shoulderOffset)
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("tyrogue", "faint") else null
override fun getFaintAnimation(
pokemonEntity: PokemonEntity,
state: PoseableEntityState<PokemonEntity>
) = if (state.isPosedIn(standing, walk, battleidle, sleep)) bedrockStateful("tyrogue", "faint") else null
}
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedW
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
@@ -35,6 +36,8 @@ class BeldumModel (root: ModelPart) : PokemonPoseableModel() {
lateinit var sleep: PokemonPose
lateinit var battleidle: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("beldum", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("beldum", "blink").setPreventsIdle(false)}
val quirk = quirk("quirk") { bedrockStateful("beldum", "quirk_spin").setPreventsIdle(false)}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen3
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
@@ -30,6 +31,8 @@ class MetagrossModel (root: ModelPart) : PokemonPoseableModel() {
lateinit var sleep: PokemonPose
lateinit var battleidle: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("metagross", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("metagross", "blink").setPreventsIdle(false)}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen3
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
@@ -30,6 +31,8 @@ class MetangModel (root: ModelPart) : PokemonPoseableModel() {
lateinit var sleep: PokemonPose
lateinit var battleidle: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("metang", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("metang", "blink").setPreventsIdle(false)}
@@ -8,64 +8,87 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen3
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class MightyenaModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, QuadrupedFrame {
class MightyenaModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("mightyena")
override val head = getPart("head")
override val hindLeftLeg = getPart("leg_left")
override val hindRightLeg = getPart("leg_right")
override val foreLeftLeg = getPart("arm_left")
override val foreRightLeg = getPart("arm_right")
override val portraitScale = 2.2F
override val portraitTranslation = Vec3d(-0.8, 0.6, 0.0)
override val profileScale = 0.6F
override val profileTranslation = Vec3d(0.0, 0.8, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var battleidle: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("mightyena", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("mightyena", "blink").setPreventsIdle(false) }
val laugh_out_battle = quirk("laugh_out_battle", secondsBetweenOccurrences = 120F to 240F) { bedrockStateful("mightyena", "quirk").setPreventsIdle(false) }
val laugh_in_battle = quirk("laugh_in_battle", secondsBetweenOccurrences = 30F to 60F) { bedrockStateful("mightyena", "quirk").setPreventsIdle(false) }
val sleep_quirk = quirk("sleep_quirk", secondsBetweenOccurrences = 30F to 60F) { bedrockStateful("mightyena", "sleep_quirk").setPreventsIdle(false) }
sleep = registerPose(
poseType = PoseType.SLEEP,
quirks = arrayOf(sleep_quirk),
idleAnimations = arrayOf(bedrock("mightyena", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = UI_POSES + STATIONARY_POSES,
quirks = arrayOf(blink),
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
condition = { !it.isBattling },
quirks = arrayOf(blink,laugh_out_battle),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("mightyena","ground_idle")
bedrock("mightyena", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
poseTypes = PoseType.MOVING_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
QuadrupedWalkAnimation(this, periodMultiplier = 0.8F, amplitudeMultiplier = 0.8F),
bedrock("mightyena","ground_idle")
bedrock("mightyena", "ground_walk")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink,laugh_in_battle),
condition = { it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("mightyena", "battle_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("mightyena", "faint") else null
override fun getFaintAnimation(
pokemonEntity: PokemonEntity,
state: PoseableEntityState<PokemonEntity>
) = bedrockStateful("mightyena", "faint")
}
@@ -49,7 +49,7 @@ class ShroomishModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
quirks = arrayOf(blink),
condition = { it.isBattling },
condition = { !it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("shroomish", "ground_idle")
@@ -68,7 +68,6 @@ class VolbeatModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
poseTypes = setOf(PoseType.HOVER, PoseType.FLOAT),
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isTouchingWater },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("volbeat", "air_idle")
@@ -80,7 +79,6 @@ class VolbeatModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
poseTypes = setOf(PoseType.FLY, PoseType.SWIM),
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isTouchingWater },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("volbeat", "air_fly")
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class DrifblimModel (root: ModelPart) : PokemonPoseableModel() {
override val rootPart = root.registerChildWithAllChildren("drifblim")
override val portraitScale = 0.9F
override val portraitTranslation = Vec3d(-0.35, 1.8, 0.0)
override val profileScale = 0.4F
override val profileTranslation = Vec3d(0.0, 1.1, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var sleep: PokemonPose
override fun registerPoses() {
val blink = quirk(name = "blink") { bedrockStateful("drifblim", "blink").setPreventsIdle(false) }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("drifblim", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
transformTicks = 10,
idleAnimations = arrayOf(
bedrock("drifblim", "ground_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("drifblim", "faint") else null
}
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class DrifloonModel (root: ModelPart) : PokemonPoseableModel() {
override val rootPart = root.registerChildWithAllChildren("drifloon")
override val portraitScale = 1.5F
override val portraitTranslation = Vec3d(-0.1, 1.2, 0.0)
override val profileScale = 0.5F
override val profileTranslation = Vec3d(0.0, 0.9, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var sleep: PokemonPose
override fun registerPoses() {
val blink = quirk(name = "blink") { bedrockStateful("drifloon", "blink").setPreventsIdle(false) }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("drifloon", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
transformTicks = 10,
idleAnimations = arrayOf(
bedrock("drifloon", "ground_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("drifloon", "faint") else null
}
@@ -8,12 +8,16 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import com.cobblemon.mod.common.client.render.models.blockbench.asTransformed
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.TransformedModelPart
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
@@ -34,6 +38,10 @@ class TurtwigModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quad
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var shoulderLeft: PokemonPose
lateinit var shoulderRight: PokemonPose
val shoulderOffset = 3
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("turtwig", "cry").setPreventsIdle(false) }
@@ -65,5 +73,33 @@ class TurtwigModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quad
bedrock("turtwig", "ground_walk")
)
)
shoulderLeft = registerPose(
poseType = PoseType.SHOULDER_LEFT,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("turtwig", "shoulder_left")
),
transformedParts = arrayOf(
rootPart.asTransformed().addPosition(TransformedModelPart.X_AXIS, shoulderOffset)
)
)
shoulderRight = registerPose(
poseType = PoseType.SHOULDER_RIGHT,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("turtwig", "shoulder_right")
),
transformedParts = arrayOf(
rootPart.asTransformed().addPosition(TransformedModelPart.X_AXIS, -shoulderOffset)
)
)
}
override fun getFaintAnimation(
pokemonEntity: PokemonEntity,
state: PoseableEntityState<PokemonEntity>
) = bedrockStateful("turtwig", "faint")
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class ChandelureModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("chandelure")
override val head = getPart("head")
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(-0.3, -1.2, 0.0)
override val profileScale = 0.8F
override val profileTranslation = Vec3d(0.0, 0.5, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
override fun registerPoses() {
// val blink = quirk("blink") { bedrockStateful("chandelure", "blink").setPreventsIdle(false) }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
// quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("chandelure", "idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
// quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("chandelure", "idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("chandelure", "faint") else null
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class LampentModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("lampent")
override val head = getPart("head")
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(-0.3, -1.2, 0.0)
override val profileScale = 0.8F
override val profileTranslation = Vec3d(0.0, 0.5, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("lampent", "blink").setPreventsIdle(false) }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("lampent", "idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("lampent", "idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("lampent", "faint") else null
}
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class LitwickModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("litwick")
override val head = getPart("head")
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(-0.3, -1.2, 0.0)
override val profileScale = 0.8F
override val profileTranslation = Vec3d(0.0, 0.5, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("litwick", "blink").setPreventsIdle(false) }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("litwick", "idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("litwick", "idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("litwick", "faint") else null
}
@@ -41,9 +41,10 @@ class TrevenantModel (root: ModelPart) : PokemonPoseableModel() {
poseType = PoseType.SLEEP,
idleAnimations = arrayOf(bedrock("trevenant", "sleep"))
)
standing = registerPose(
poseName = "stand",
poseTypes = PoseType.STATIONARY_POSES - PoseType.HOVER - PoseType.FLOAT + PoseType.UI_POSES,
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
condition = { !it.isBattling },
transformTicks = 10,
quirks = arrayOf(blink),
@@ -53,7 +54,7 @@ class TrevenantModel (root: ModelPart) : PokemonPoseableModel() {
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES - PoseType.FLY - PoseType.SWIM,
poseTypes = PoseType.MOVING_POSES,
transformTicks = 5,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
@@ -25,7 +25,6 @@ class KomalaModel (root: ModelPart) : PokemonPoseableModel() {
override val profileScale = 0.8F
override val profileTranslation = Vec3d(0.0, 0.5, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
// override val cryAnimation = CryProvider { _, _ -> bedrockStateful("komala", "cry").setPreventsIdle(false) }
@@ -62,5 +62,5 @@ class EiscueModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override fun getFaintAnimation(
pokemonEntity: PokemonEntity,
state: PoseableEntityState<PokemonEntity>
) = if (state.isPosedIn(standing, walk, sleep)) bedrockStateful("eiscue_ice", "faint") else null
) = bedrockStateful("eiscue_ice", "faint")
}
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedW
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
@@ -37,6 +38,8 @@ class QuaxwellModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
lateinit var sleep: PokemonPose
lateinit var battleidle: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("quaxwell", "cry").setPreventsIdle(false) }
override fun registerPoses() {
val blink = quirk("blink") { bedrockStateful("quaxwell", "blink").setPreventsIdle(false) }
sleep = registerPose(
Loaded 100 of 1157 files, more files were not shown because too many files have changed in this diff. Show more