Compare commits

..
Author SHA1 Message Date
Gitoido 61d53f3052 Merge branch 'main' into 'steppy-steps'
# Conflicts:
#   common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
2026-10-09 16:19:32 +00:00
Polymeta d02441a273 Merge branch 'fix/mooshtank-checks' into 'main'
fix: added checks for mooshtank aspect, denying usage of bowl on common miltanks

See merge request cable-mc/cobblemon!2468
2026-10-09 15:25:11 +00:00
Gitoido f76ab784b5 fix: item stack must be copied into lastFlowerFed 2026-10-09 18:06:43 +03:00
Polymeta a566e36754 Merge branch 'fix/tms-consumption-tmm-screen' into 'main'
fix: tm stack not consumed on use in tmm screen

See merge request cable-mc/cobblemon!2466
2026-10-09 14:31:51 +00:00
Polymeta ef1479fde6 Merge branch 'fix/equip-one-not-whole' into 'main'
fix: equipping stackable items now equips one item of stack

See merge request cable-mc/cobblemon!2469
2026-10-09 14:31:02 +00:00
Gitoido d6c7b271e4 chore: flip when condition for readability 2026-10-09 11:11:34 +03:00
Gitoido df9acfa0d1 fix: equipping stackable items now equips one item of stack 2026-10-09 11:03:06 +03:00
Polymeta 9d7fc8435e scraped spawns again and pokemon that are part of herd will also get their specific drops
Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-10-09 08:23:40 +01:00
Gitoido ab4492ac5c fix: forgor clientside level check 2026-10-09 09:43:38 +03:00
Gitoido cb78dc8d88 fix: flower should be consumed when feeding brown mooshtank 2026-10-09 09:42:44 +03:00
Gitoido 020adabe26 fix: added checks for mooshtank aspect, denying usage of bowl on common miltanks 2026-10-09 09:33:03 +03:00
Gitoido 08aca7a274 chore: changelog skip-ci 2026-10-09 09:14:02 +03:00
Gitoido 2a9ef2b9fe fix: increment menu state id on held tm stack click, small code cleanup 2026-10-09 08:39:46 +03:00
Polymeta 5ec5cfbc4a Merge branch 'fix/bees-grow-apricorns-galarica' into 'main'
Fixed bees not growing Apricorns or the Galarica Nut Bush

Closes #2095

See merge request cable-mc/cobblemon!2427
2026-10-08 14:59:41 +00:00
Polymeta 1ef65449a8 Merge branch 'fix/addon-species-namespaces' into 'main'
Fix crashes with addon-namespace species in evolution, bait and Pokédex lookups

Closes #1353

See merge request cable-mc/cobblemon!2465
2026-10-08 14:56:31 +00:00
Fyre520 c6ff1ea72e Fix crashes with addon-namespace species in evolution, bait and Pokédex lookups 2026-10-08 18:50:53 +05:30
Polymeta cbfa8d3e78 Merge branch 'fix/alpha-chance-config-category' into 'main'
fix: config category for alpha/shiny chance config fields for fossil machine...

See merge request cable-mc/cobblemon!2464
2026-10-08 09:45:34 +00:00
Gitoido 5098ff3cfd fix: config category for alpha/shiny chance config fields for fossil machine and honey log slathering should be Spawning 2026-10-08 12:27:35 +03:00
Polymeta 7c32b07d3f scraped spawns
Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-10-08 08:42:43 +01:00
Polymeta 6fba0f55c1 Merge branch 'fix/recall-beam-3rdperson' into 'main'
fix: optimize condition checker for recall beam source position

See merge request cable-mc/cobblemon!2462
2026-10-08 06:48:03 +00:00
Polymeta 0be617b8ab Merge branch 'fix/1359-sweep-fire-owned-pokemon' into 'main'
Fix sweeping attacks igniting owned Pokémon

Closes #1359

See merge request cable-mc/cobblemon!2460
2026-10-08 06:08:35 +00:00
Polymeta c02d22f449 Merge branch 'fix/1492-edible-medicinal-leek' into 'main'
Fix Medicinal Leek not being edible

Closes #1492

See merge request cable-mc/cobblemon!2459
2026-10-08 06:03:59 +00:00
Polymeta 846b645856 Merge branch 'type-gem-min-growth-fix' into 'main'
fix wrong value in CobblemonConfig for type gem min growth

See merge request cable-mc/cobblemon!2461
2026-10-08 06:01:53 +00:00
whatsyandPolymeta 25d93a771c fix wrong value in CobblemonConfig for type gem min growth 2026-10-08 06:01:53 +00:00
Gitoido f16c782336 fix: optimize condition checker for recall beam source position 2026-10-08 08:56:53 +03:00
shg ed0f315e41 Fix sweeping attacks igniting owned Pokémon
Closes #1359
2026-10-08 00:42:28 +00:00
shg d20b03f4c5 Fix Medicinal Leek not being edible
Closes #1492
2026-10-08 00:42:25 +00:00
Polymeta a3920413ac fix TMM UI not closing when supposed to 2026-10-07 21:48:28 +00:00
Polymeta dfb9ee755e Merge branch 'Slippy-1.8.2-Fixes' into 'main'
Slippy 1.8.2 fixes

See merge request cable-mc/cobblemon!2458
2026-10-07 17:25:48 +00:00
Slippy 68f4117e29 Focus Sash changed to focus band in ruin sus loot 2026-10-07 12:09:05 -05:00
Slippy f74a24a056 Console Log Spam Fix 2026-10-07 12:06:19 -05:00
Slippy b4c23a9132 Alpha Loot Table nerfed 2026-10-07 11:34:35 -05:00
Polymeta 9af99d16f7 Merge branch 'feature/the-center-of-attention' into 'main'
constraining should start from center of spawn area

Closes #2119

See merge request cable-mc/cobblemon!2457
2026-10-07 07:17:30 +00:00
Polymeta 2cc17d3280 constraining should start from center of spawn area 2026-10-07 07:17:30 +00:00
Polymeta 20b2bcaa5a Merge branch 'implement_pokemon' into 'main'
Implement pokemon

See merge request cable-mc/cobblemon!2455
2026-10-06 11:47:36 +00:00
Kenji_64 d1ada605fd Fixed Alolan Bias Pichu resolver issues (again) 2026-10-06 13:20:30 +02:00
Polymeta d37f73626d Merge branch 'type-gem-growth-rework' into 'main'
Type gem growth rework

See merge request cable-mc/cobblemon!2451
2026-10-06 07:07:32 +00:00
Polymeta 73a94cb02e Merge branch 'burmy-cloak-change' into 'implement_pokemon'
Burmy Cloak Changing & Battle Ended Event Refinements

See merge request cable-mc/cobblemon!2452
2026-10-06 07:04:32 +00:00
Polymeta 5a48945e50 Merge branch 'fix/particles-respecting-graphics-setting' into 'main'
fix: particle density should respect minecraft particle density settings

See merge request cable-mc/cobblemon!2446
2026-10-06 05:49:29 +00:00
Polymeta 476448a2ce Merge branch 'more-block-noises' into 'main'
More more item blocks sounds

See merge request cable-mc/cobblemon!2450
2026-10-06 05:48:55 +00:00
Polymeta bcba4f7fb7 Merge branch 'implement_pokemon' into 'main'
implement_pokemon

See merge request cable-mc/cobblemon!2445
2026-10-06 05:47:25 +00:00
Konoha 20e9608ff3 cleanup: biome tag overlaps and priority 2026-10-05 22:08:49 -04:00
ewwww 3e5733ceaf GREAVARD EMISSIVES 2026-10-05 19:29:25 -04:00
ewwww af29c99b03 properly defined vivillon's pattern forms as forms viewable in the pokedex with form names and dex entries 2026-10-05 18:42:09 -04:00
ewwww 60d596a24f riolu + lucario remodels 2026-10-05 17:14:24 -04:00
Konoha 3f993e0466 feature: Burmy cloak changing (and battle event refinements) 2026-10-05 12:21:18 -04:00
whatsy 9e3d22ee54 default type gem cluster growth type is decoration, so porting doesn't give people an infinite gem block glitch 2026-10-05 11:04:59 -04:00
whatsy e86cb1981f Merge remote-tracking branch 'origin/type-gem-growth-rework' into type-gem-growth-rework 2026-10-05 10:55:16 -04:00
jackowesandwhatsy e94f265adb Add datafixer for type gems. Also ensure the fix runs even when mc version stays the same 2026-10-05 10:55:00 -04:00
whatsy b3fc35240a no i didnt forget the changelog 2026-10-05 10:55:00 -04:00
whatsy d74618bddb basically finalized 2026-10-05 10:55:00 -04:00
whatsy 8b54a8d459 moved stuff to config + more adjustments 2026-10-05 10:55:00 -04:00
whatsy c17104a0fd Basics for the type gem growth rework 2026-10-05 10:55:00 -04:00
Sterrezo 88ca3ebbf3 Added item block sound sets for glass jars with liquid 2026-10-05 15:14:53 +02:00
ewwww 4003456e5c slakoth animations + minor model tweaks 2026-10-05 05:41:06 -04:00
ewwww 1d21a52d28 shinx, luxio, and luxray remodels 2026-10-05 05:38:23 -04:00
ewwww 2d49c62f85 froakie, frogadier, greninja, & ash-greninja remodels + greninja animations 2026-10-05 05:38:23 -04:00
Polymeta 20fac724f6 Merge branch 'testing-fixes' into 'main'
Small Fixes

See merge request cable-mc/cobblemon!2448
2026-10-05 07:02:45 +00:00
dhi_holoandPolymeta 0807d73646 Small Fixes 2026-10-05 07:02:45 +00:00
Jackson Bowes 3013302f35 Merge branch 'drained' into 'main'
Mega Doinked

See merge request cable-mc/cobblemon!2447
2026-10-04 19:22:42 -05:00
dhi_holo 879e7bef21 Mega Doinked
Removes Mega Drain as a TM, due to only being learnt by a single line of Pokemon
2026-10-05 10:04:29 +10:00
jackowes 557623dfe2 Add datafixer for type gems. Also ensure the fix runs even when mc version stays the same 2026-10-04 15:01:49 -05:00
Gitoido a28d1e176d chore: remove log spam skip-ci 2026-10-04 18:24:18 +03:00
Gitoido f3c52db70d chore: changelog + unused imports cleanup skip-ci 2026-10-04 18:22:22 +03:00
Gitoido 525575b0ba fix: particle density should respect minecraft particle density settings 2026-10-04 18:10:54 +03:00
Sterrezo a55efeb378 Added metal can item block sounds, fixed missing sound implementation for a bunch of other item block sounds 2026-10-04 15:44:04 +02:00
Kenji_64 da18b082a6 Fixed Alolan Bias Pichu and Pikachu referring to the wrong models and removed the old ones 2026-10-04 12:49:46 +02:00
Polymeta 7511facebc Merge branch 'decorative-items-for-all' into 'main'
More Decorative Items

See merge request cable-mc/cobblemon!2430
2026-10-04 06:58:14 +00:00
dhi_holo 1486f5cfc2 Merge branch 'main' into decorative-items-for-all 2026-10-04 12:43:57 +10:00
ewwww f8a16e5081 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-10-03 22:23:06 -04:00
dhi_holo 558e2d89ff Mipmap Fix
shhhh, I did it the cheap and nasty way rather than tweaking the models, it's for the greater good though
2026-10-04 12:01:29 +10:00
dhi_holo ea7b688655 Asset Updates 2026-10-04 11:35:22 +10:00
Polymeta fdafa3435c Merge branch 'flora-heals-an-aching-soul-' into 'main'
Flora Update

See merge request cable-mc/cobblemon!2412
2026-10-04 00:02:50 +00:00
dhi_holo f17c90f6ea Changelog
(also fixed some issues from the merge conflicts I missed)
2026-10-04 09:14:54 +10:00
dhi_holo 1dc45669bb Recipe Updates the Third 2026-10-04 09:14:12 +10:00
dhi_holo f3658614a4 Merge branch 'main' into decorative-items-for-all 2026-10-04 08:35:05 +10:00
Polymeta cad39d8802 Merge branch 'form-move-fix' into 'implement_pokemon'
Form Move Fix

See merge request cable-mc/cobblemon!2420
2026-10-03 22:33:27 +00:00
Polymeta 422f60f587 Merge branch 'feat/tm-creative-tab' into 'main'
Add Technical Machines creative tab

See merge request cable-mc/cobblemon!2443
2026-10-03 22:31:41 +00:00
dhi_holo 8190ddf0e9 Merge branch 'main' into flora-heals-an-aching-soul- 2026-10-04 08:31:26 +10:00
dhi_holo af281d0bde Pa'uvillea 2026-10-04 07:57:39 +10:00
Kenji_64 00905b8c32 Oops, fixed Pikachu's walk 2026-10-03 21:54:11 +02:00
ewwww 79b3cb8611 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-10-03 15:47:45 -04:00
ewwww 797e908621 restored placeholder animations for chespin and quilladin 2026-10-03 15:47:40 -04:00
Kenji_64 3df3c395de Cap Animations for the entire Pikachu line, updated Raichu animations, added faint to Pikachu and 1 new cosmetic for Pikachu!!! 2026-10-03 21:25:11 +02:00
whatsy b2f682ebb1 no i didnt forget the changelog 2026-10-03 15:09:15 -04:00
Gitoido 754e9bc158 chore: changelog skip_ci 2026-10-03 20:48:36 +03:00
Gitoido 2df8504139 feat: lore correct sorting 2026-10-03 20:35:44 +03:00
Gitoido 2838f97c56 feat: add Technical Machines dynamic creative tab 2026-10-03 19:55:32 +03:00
Gitoido 68c75deeeb feat: Technical Machines creative tab i18n 2026-10-03 19:55:04 +03:00
whatsy 3bc2659740 basically finalized 2026-10-02 22:42:57 -04:00
Konoha 89bba8a67a Quick fix changelog and sneaky Spinda fix 2026-10-02 20:51:52 -04:00
whatsy cbd5cdaf92 moved stuff to config + more adjustments 2026-10-02 14:01:04 -04:00
Jerzykv 6d6e13be83 Changelog 2026-10-02 09:29:46 +02:00
Jerzykv 899bec77b6 Implemented Fennekin, Braixen and Delphox remodels 2026-10-02 09:28:58 +02:00
Jerzykv 6dd8325772 Implemented Chespin, Quilladin and Chesnaught remodels 2026-10-02 09:28:39 +02:00
dhi_holo e9bffd3ad7 Minty Fresh
Updated Mint Leaf Litter to use a texture closer to Vanilla to make the tiling nicer
2026-10-02 17:18:54 +10:00
dhi_holo 460c472c55 Asset Updates
Approved assets for all Terrain Plants, Mint Leaf Litter, and three of the nectar flowers (at my own fault). Potted plants already match approval
2026-10-02 16:09:11 +10:00
dhi_holo 69c3b6142d Merge branch 'main' into flora-heals-an-aching-soul- 2026-10-02 14:56:06 +10:00
whatsy 0fbe206893 Basics for the type gem growth rework 2026-10-01 23:46:18 -04:00
Sterrezo 2aa4ab4b52 Added sounds to bright powder illuminating signs 2026-10-01 17:40:13 +02:00
Gitoido 113977990e feat: helper functions to register plants and pots 2026-10-01 17:22:09 +03:00
dhi_holo 3bd3ce5688 Delete wisteria_root_side.json 2026-09-30 10:58:27 +10:00
dhi_holo 881a87216b Merge branch 'main' into flora-heals-an-aching-soul- 2026-09-30 10:11:19 +10:00
dhi_holo 1d473b82af Refactor
Renamed Voltconia to Voltaconia, and also fixed the models being in a temp folder for easier file editing because that's not needed anymore
2026-09-30 10:10:55 +10:00
Konoha 6e0c005587 Changelog 2026-09-29 16:25:13 -04:00
Fantastic-Fanta 3b722068b0 Fixed bees not growing Apricorns or the Galarica Nut Bush
Bonemealable blocks in the bee growables tag are now grown through performBonemeal, with the nectar and particle updates vanilla skips.

Closes #2095
2026-09-29 11:25:59 +08:00
dhi_holo b426df7271 A Metric Buttton of Tagging
Added a bunch of tags, IDs, and redundancies, it doesn't cover everything but it should cover a lot of the base game without much worry
2026-09-28 10:29:50 +10:00
Sterrezo 1543e06a06 Update CHANGELOG.md 2026-09-27 14:56:17 +02:00
Sterrezo d7b4ccb1e5 Update corviknight.animation.json 2026-09-27 14:46:07 +02:00
Sterrezo dedd449329 Update corviknight.animation.json 2026-09-27 14:45:31 +02:00
Sterrezo 38c589658f Finalized assets and added amethyst stepsounds it'S FINALLY DONE 2026-09-27 14:44:29 +02:00
Sterrezo 2f961bd7bf Expanded on all stepsounds to cover metal surfaces 2026-09-26 23:52:15 +02:00
Sterrezo b72244a986 Added large and medium claw stepsounds for glass surfaces 2026-09-26 19:42:06 +02:00
Sterrezo 6710f25190 Added medium and large claw stepsounds for mud, wood and snow surfaces, updated mud hoof stepsounds 2026-09-26 15:44:32 +02:00
Sterrezo 4089e5d7a9 Added medium and large claw stepsounds for dirt and sand surfaces, updated stone claw stepsounds 2026-09-26 11:54:45 +02:00
Sterrezo 0a49b5b17b Added medium and large claw stepsounds for stone surfaces, updated grass claw stepsounds 2026-09-25 16:57:06 +02:00
Sterrezo 34c40de429 Suppressed Pidgeot's and Corviknight's Minecraft stepsounds 2026-09-25 12:03:03 +02:00
Sterrezo 6d02144401 Updated grass claw stepsound assets 2026-09-25 12:01:42 +02:00
Sterrezo 561687ce0f Added stepsounds to Pidgeot's ride walk animations 2026-09-25 11:30:28 +02:00
dhi_holo e0d0c38232 Merge branch 'main' into decorative-items-for-all 2026-09-25 15:02:09 +10:00
Sterrezo 20973c6724 Added stepsound keyframes to Pidgeot, added medium and large claw stepsounds for grass surfaces 2026-09-24 22:44:15 +02:00
Sterrezo bf10a4dcef Added medium and large hoof stepsounds for glass and ice surfaces 2026-09-24 21:23:37 +02:00
Sterrezo 565987a780 Added standard medium and large stepsounds for glass/ice surfaces, updated mud hoof sounds 2026-09-23 14:49:34 +02:00
Sterrezo 4f9a6c8e98 Added medium and large hoof stepsounds for mud surfaces 2026-09-23 10:46:56 +02:00
Sterrezo 3a3e92d441 Update CHANGELOG.md 2026-09-23 00:38:26 +02:00
Sterrezo bc0dc809f9 Merge branch 'main' into steppy-steps 2026-09-23 00:37:33 +02:00
Sterrezo 92310847aa Footsteps now check from depth 0 instead of 1 2026-09-23 00:08:37 +02:00
Polymeta 5bdc59830c change standingOn logic to consider non-full blocks
Signed-off-by: Polymeta <4726322-polymeta@users.noreply.gitlab.com>
2026-09-22 22:44:09 +01:00
Sterrezo 17f524d3da Added standard medium and large stepsounds for mud surfaces 2026-09-22 18:45:29 +02:00
Sterrezo 4d0de2bb45 Corrected the size sound variation for leaves stepsounds 2026-09-22 15:52:05 +02:00
Sterrezo b3b8f56bb8 Made block tags optional 2026-09-22 15:45:46 +02:00
Sterrezo f036b83693 Added universal stepsounds for leaves 2026-09-22 15:34:17 +02:00
Sterrezo 73fb31c2fc Added hoof stepsounds for wood surfaces 2026-09-22 10:49:03 +02:00
Sterrezo 381787f39d Updated standard wood stepsounds 2026-09-22 10:24:12 +02:00
dhi_holo 217d4cda42 Update CHANGELOG.md 2026-09-22 10:44:12 +10:00
dhi_holo 08daa43aae Update blank_tm.json 2026-09-22 10:41:01 +10:00
dhi_holo 184d889831 TM Boost 2026-09-22 10:36:59 +10:00
dhi_holo c6e0f431ae Update never_melt_ice.json 2026-09-22 10:31:59 +10:00
dhi_holo 93daeab840 Merge branch 'main' into decorative-items-for-all 2026-09-22 10:16:29 +10:00
dhi_holo f132b297c6 Never-Melted
Recipe Update
2026-09-22 10:16:17 +10:00
dhi_holo c0a524a718 Jars and Generators and a forgotten Pouch
6 new items ready to decorate your worlds
2026-09-21 11:58:11 +10:00
Konoha f445c05333 fix: Quick-fix For #updateMovesOnFormChange 2026-09-17 17:38:02 -04:00
Konoha a62485fc1f Fix Calyrex form moves 2026-09-17 15:14:27 -04:00
Konoha 044f3080ff Fix Hoopa form moves 2026-09-17 15:09:43 -04:00
Konoha 28b0cab906 Adjust Form Change moves for Kyurem's level-gated ones. 2026-09-17 14:35:15 -04:00
Konoha 82f34d651c Add Kyurem's form moves 2026-09-17 14:32:47 -04:00
dhi_holo 92b0ef84e9 Yeah, I've Got Time
This'll hopefully be ready in time for 1.8.2 so I'm making the decision to treat it as if it is now, so it almost certainly will be
2026-09-14 16:37:09 +10:00
dhi_holo dc8d18384c Merge branch 'main' into flora-heals-an-aching-soul- 2026-09-14 16:33:26 +10:00
dhi_holo 44c056ecd5 Update CHANGELOG-DecorativeWv2.md
Fixed that up for cleanup reasons
2026-09-14 11:34:16 +10:00
dhi_holo dcc707c20d Model Fix
Improved the visuals and log spam of the Wistensu blocks
2026-09-14 10:53:12 +10:00
Gertimoshka 07b1b22c2c Wistensu Flower Logic Implementation 2026-09-13 15:08:44 +02:00
dhi_holo 23078eccba Wistensu Root Models
Fixed a tag and added the models for the Wistensu Roots
2026-09-13 21:11:11 +10:00
dhi_holo 8a82f35edf Seasonings 2026-09-13 19:59:19 +10:00
dhi_holo bec664c073 Merge Conflict Fixes 2026-09-13 13:01:20 +10:00
dhi_holo 3e61424d8f Merge branch 'main' into flora-heals-an-aching-soul- 2026-09-13 12:28:17 +10:00
dhi_holo c1606c6fc9 Textures!
Terrain Plants now have proper textures, finishing them off beyond some data file work waiting on some conversations
2026-09-13 11:42:42 +10:00
dhi_holo e0108cc99f Merge branch 'main' into flora-heals-an-aching-soul- 2026-09-13 10:47:37 +10:00
dhi_holo c0de8a2591 Update TerrainSeedBlock.kt
Actually fixed it this time
2026-09-12 15:19:09 +10:00
dhi_holo b8733eed52 Revert "Update TerrainSeedBlock.kt"
This reverts commit bd0511a9fb.
2026-09-12 14:31:19 +10:00
dhi_holo 4aa30efec7 Merge branch 'main' into flora-heals-an-aching-soul- 2026-09-12 13:04:47 +10:00
Sterrezo 2cb942a24b Merge branch 'main' into steppy-steps 2026-09-10 21:26:50 +02:00
Sterrezo c79cb5731e Missclicked 2026-09-10 18:14:43 +02:00
Sterrezo 4760bb15a4 Added standard medium and large footsteps for wood surfaces 2026-09-10 18:14:28 +02:00
Sterrezo aac881f23c Added large and medium hoof footstep sounds 2026-09-09 18:31:27 +02:00
Sterrezo da19c51566 Implemented standard medium and large snow footsteps 2026-09-09 17:58:27 +02:00
dhi_holo 7930ec52fa Merge branch 'main' into flora-heals-an-aching-soul- 2026-09-07 15:20:47 +10:00
dhi_holo 57eb306e4f Update TODO List - Flora Heals An Aching Soul.md 2026-09-06 21:25:18 +10:00
dhi_holo bd0511a9fb Update TerrainSeedBlock.kt
Terrain crops now break properly after growing to be 2 blocks tall
2026-09-06 21:24:28 +10:00
dhi_holo c14f3292aa Merge branch 'main' into flora-heals-an-aching-soul- 2026-09-06 19:57:15 +10:00
Sterrezo 37dd354155 Merge branch 'main' into steppy-steps 2026-09-06 11:12:32 +02:00
dhi_holo 8fb2b1cf3d Merge branch 'main' into flora-heals-an-aching-soul- 2026-07-12 08:20:14 +10:00
dhi_holo 5c7d1cbe10 Fixed Case of the Missing Loot Table 2026-06-04 15:47:55 +10:00
dhi_holo 3348bfc362 Merge branch 'main' into flora-heals-an-aching-soul- 2026-06-04 14:35:35 +10:00
Sterrezo acb1ebda19 Finalized hoof sounds 2026-05-27 12:34:57 +02:00
Sterrezo 5dddc05626 Merge branch 'main' into steppy-steps 2026-05-27 00:16:42 +02:00
Sterrezo 99890671bd Added hoof footsteps for sand surfaces and updated other hoof sounds 2026-05-26 22:21:56 +02:00
Sterrezo 9451ac5f46 Merge branch 'main' into steppy-steps 2026-05-26 21:42:41 +02:00
dhi_holo 8db9252434 Potted Berries for All 2026-05-25 18:09:49 +10:00
dhi_holo d9d4fe15cc Update TODO List - Flora Heals An Aching Soul.md 2026-05-25 08:40:11 +10:00
dhi_holo 8453e2d514 Milling Integration
with Create
2026-05-25 08:15:47 +10:00
dhi_holo 4d3070c0c2 Compost Levels 2026-05-25 08:03:54 +10:00
dhi_holo 15f273a9ef Bright Powder on Signs
It's so wonderful
2026-05-25 07:16:36 +10:00
dhi_holo 007c079cd6 WIP 2026-05-25 05:17:30 +10:00
dhi_holo 9851b1e8ad Merge branch 'main' into flora-heals-an-aching-soul- 2026-05-25 04:22:38 +10:00
Sterrezo a8e4e21ba1 Merge branch 'main' into steppy-steps 2026-05-19 14:15:48 +02:00
Sterrezo f555ba3703 Made Molang slightly less cursed with proper random functions 2026-05-16 14:24:18 +02:00
dhi_holo c65c2610cd Merge branch 'main' into flora-heals-an-aching-soul- 2026-05-16 21:29:13 +10:00
dhi_holo 2be08a3fcc terminology corrections
also tag additions
2026-05-16 21:26:05 +10:00
Sterrezo 37677b3730 Asset updates, added hoof on stone sounds 2026-05-16 12:17:24 +02:00
Sterrezo 2a298b2268 Merge branch 'main' into steppy-steps 2026-05-16 11:01:28 +02:00
Sterrezo ad3f94fb80 Added hoof grass medium and large sounds 2026-05-16 02:27:46 +02:00
Sterrezo 719660798e Started hoof sound implementation with Wyrdeer, asset and keyframe updates 2026-05-15 18:17:04 +02:00
Sterrezo 8d973a09e1 Tweaks to the footstep function logic to better account for depth
If depth is 2 outright, the function could pick a block below the actual block the entity is standing on if it was checked earlier in the function. Loop iterates twice, so now it plays footsteps even when standing on the edge of a block or running down slopes.
2026-05-15 11:48:50 +02:00
Sterrezo 3579a86cde Merge branch 'main' into steppy-steps 2026-05-15 11:08:00 +02:00
Sterrezo ba96a6a205 Added standard medium and large sand footsteps 2026-05-14 20:18:04 +02:00
Sterrezo f07d2a9a9a First implementation of footstep keyframes with Arcanine 2026-05-14 16:56:13 +02:00
Sterrezo 2469067fd4 Allow for silencing step sounds within the species file 2026-05-14 02:24:18 +02:00
dhi_holo 4cdf440eee More Tagging Work 2026-05-13 09:48:52 +10:00
dhi_holo 1545ee8fc2 Merge branch 'main' into flora-heals-an-aching-soul- 2026-05-13 09:12:37 +10:00
dhi_holo a009fabfe4 Create TODO List - Flora Heals An Aching Soul.md 2026-05-12 22:51:33 +10:00
dhi_holo 46e4bfdd13 CONSUME 2026-05-12 22:27:07 +10:00
dhi_holo e24c82860d No Bone 2026-05-12 22:11:53 +10:00
dhi_holo 1291dee1e1 Data Files 2026-05-12 21:39:03 +10:00
dhi_holo 69732be09b Mistleaf's Fae Magics 2026-05-12 18:24:23 +10:00
dhi_holo 8ce4ed7dee Update TerrainFlowerBlock.kt
Removed unused imports
2026-05-12 14:59:52 +10:00
dhi_holo 33d3cc0104 Merge branch 'flora-heals-an-aching-soul-' of https://gitlab.com/cable-mc/cobblemon into flora-heals-an-aching-soul- 2026-05-12 14:52:36 +10:00
dhi_holo 33b6b519ed Merge branch 'flora-heals-an-aching-soul-' of https://gitlab.com/cable-mc/cobblemon into flora-heals-an-aching-soul- 2026-05-12 12:26:39 +10:00
dhi_holo 5ec849f4e3 Merge branch 'main' into flora-heals-an-aching-soul- 2026-05-12 12:26:09 +10:00
Gertimoshka 6f4a2d2cd5 Made the flowers block entities so they can tick and adjust to weather changes 2026-05-11 21:35:48 +03:00
Gertimoshka 0bca89e77d Lucibell will now properly light up if any part of the block has an entity in it, by designating lower part as the 'driver' who controls the states 2026-05-11 17:21:22 +03:00
dhi_holo 8f9f162011 Merge branch 'main' into flora-heals-an-aching-soul- 2026-05-11 09:56:11 +10:00
dhi_holo ac3bea3d5e Update TerrainFlowerBlock.kt
Compacted but it STILL DOESN'T WORK
2026-05-10 21:23:17 +10:00
dhi_holo 178d4f199b Update TerrainFlowerBlock.kt
I feel so close, but the weather checks don't work
2026-05-09 23:04:07 +10:00
dhi_holo 933819380d Merge branch 'main' into flora-heals-an-aching-soul- 2026-05-09 21:15:27 +10:00
dhi_holo d68131e1b9 Update TerrainFlowerBlock.kt
It's starting to get there, probably. Not fully functional yet
2026-05-09 21:15:04 +10:00
dhi_holo ffbc379c0b Some More Work 2026-05-08 14:01:31 +10:00
dhi_holo 7053d12508 Update TerrainSeedBlock.kt
In theory this makes it grow slower on dry dirt, which would be pretty cool
2026-05-07 20:38:47 +10:00
dhi_holo d41442200f Models and Temp Textures and start of some code for glowing 2026-05-07 20:08:15 +10:00
dhi_holo d2564c343e Terrain Seed Beginnings 2026-05-04 22:43:54 +10:00
dhi_holo d1c19e8837 Visual FIxes 2026-05-04 14:30:31 +10:00
dhi_holo 0ec3bfabad Merge branch 'main' into flora-heals-an-aching-soul- 2026-05-04 11:37:59 +10:00
dhi_holo 43ffb04621 FINALLY FUCKING FIXED IT 2026-05-04 11:34:04 +10:00
dhi_holo eeaedf76a9 progress 2026-05-04 09:43:59 +10:00
dhi_holo 120fb4829a Pa'uvillea complete
Maash's tweaks to the wall version, plus placement logic working as desired (although may need further tweaks depending on feedback)
2026-05-03 11:10:00 +10:00
dhi_holo 12b93e53a7 Revenge of the Pa'uvillea 2026-05-02 22:43:34 +10:00
dhi_holo 00b17b9764 Update CobblemonBlocks.kt 2026-05-02 18:55:21 +10:00
dhi_holo 06192f809d Merge branch 'main' into flora-heals-an-aching-soul- 2026-05-02 18:54:04 +10:00
dhi_holo d09eb0d3ff Update LobailaFlowerBlock.kt 2026-04-23 08:05:13 +10:00
dhi_holo 416321679c Updated Textures 2026-04-22 20:29:02 +10:00
dhi_holo 72c4e6e54f Merge branch 'main' into flora-heals-an-aching-soul- 2026-04-19 16:45:10 +10:00
dhi_holo d3738e3424 Merge branch 'main' into flora-heals-an-aching-soul- 2025-12-13 18:45:37 +10:00
dhi_holo 2e183db903 Re-rename
Lobaila and Pa'uvillea changes
2025-12-02 12:33:55 +10:00
dhi_holo fa174b88dd OVERSIGHTS (may need to copy to another branch) 2025-12-01 17:09:00 +10:00
dhi_holo 0b4abe6d16 Texture Updates 2025-12-01 17:08:42 +10:00
dhi_holo 759fb0ecd8 Rename!
Lobalia, Pa'uvilla, and Pomohana are here!
2025-12-01 16:37:53 +10:00
dhi_holo 429e927c3f Potted Berries Part 1
All the data/asset stuff needed for Potted Berries.
Need to handle the codeside now, which will be trickier.
2025-11-30 22:27:29 +10:00
dhi_holo 643aed9133 Update HydrangeaFlowerBlock.kt
Comment
2025-11-30 12:02:26 +10:00
dhi_holo e701642de2 Hydrangea loot and tag starts 2025-11-30 12:00:14 +10:00
dhi_holo a3a03e3da6 Lobelia Polish and Hydrangea
Added start of Hydrangea flowers
2025-11-29 20:51:25 +10:00
dhi_holo 5dd3d5b552 Mint Rework
Totally reworked the Mint Leaf Litter blocks to not rely on Pink Petals due to the differences in behaviour, finally added Craspedia loot table, updated Craspedia texture, fixed Lobelia being shaded incorrectly
2025-11-29 16:20:45 +10:00
dhi_holo 1bae246e6c Gestdate
Ges updated textures
2025-11-29 14:39:30 +10:00
dhi_holo c94ef10189 Merge branch 'main' into flora-heals-an-aching-soul- 2025-11-29 14:24:30 +10:00
dhi_holo dfacf1f9df Merge branch 'main' into flora-heals-an-aching-soul- 2025-11-27 18:33:35 +10:00
dhi_holo 06c5e34f48 Merge branch 'main' into flora-heals-an-aching-soul- 2025-11-23 20:33:34 +10:00
dhi_holo 1ab8b35e98 Merge branch 'main' into flora-heals-an-aching-soul- 2025-11-23 12:50:52 +10:00
dhi_holo 261b61ee6c Updated Assets and removed TODO 2025-11-22 15:31:12 +10:00
dhi_holo 5abf8e1bab Merge branch 'main' into flora-heals-an-aching-soul- 2025-11-22 14:16:33 +10:00
dhi_holo 7c0b463637 Merge branch 'main' into flora-heals-an-aching-soul- 2025-11-21 18:14:42 +10:00
dhi_holo e156ab2432 Craspedia assets and Lobelia waterlogging
Still needs some more work done on both, but it's real nice now
2025-11-21 18:14:29 +10:00
dhi_holo 0b46a7163b Merge branch 'main' into flora-heals-an-aching-soul- 2025-11-21 13:35:16 +10:00
dhi_holo 21b76c008a Craspedia start
Needs work, but it's fully functional
2025-11-21 13:30:19 +10:00
dhi_holo b7e9f8248d Oricorio Start
Lobelia (Red) flower partially set up.
Wanna look into letting it be waterlogged, and no dye crafting recipe is set up yet
2025-11-20 19:34:10 +10:00
dhi_holo 8b21e76a36 Merge branch 'main' into flora-heals-an-aching-soul- 2025-11-20 17:06:31 +10:00
dhi_holo 515471185f Create CHANGELOG-DecorativeWv2.md 2025-11-19 19:54:49 +10:00
dhi_holo 628e8f4e5e Mint Leaf Litter and Potted Mint
"It's not fucking weed you piece of shit stoner" -Kermit the Frog

Needs some cleanup when it comes to how I've stolen the Pink Petals (due to Leaf Litter being a future block), but what we got rn is a good starting point
2025-11-19 19:42:38 +10:00
1636 changed files with 182034 additions and 27263 deletions
+61 -3
View File
@@ -3,8 +3,8 @@
### Additions
- The following items can now be placed on the ground as blocks:
- King's Rock, Galarica Cuff, Unremarkable Teacup, Masterpiece Teacup, Chipped Pot, Cracked Pot, Sachet, Metal Powder, Quick Powder, Bright Powder, Icy Rock, Heat Rock, Smooth Rock, Damp Rock, Destiny Knot, Luminous Moss, Never-Melt Ice, Wide Lens, Scope Lens, and Zoom Lens.
- Iron Ball, Metal Coat, Throat Spray, HP Up, Protein, Iron, Carbos, Calcium, Zinc, PP Up, PP Max, Upgrade, Dubious Disc, and Loaded Dice.
- King's Rock, Galarica Cuff, Unremarkable Teacup, Masterpiece Teacup, Chipped Pot, Cracked Pot, Sachet, Metal Powder, Quick Powder, Bright Powder, Soft Sand, Electirizer, Magmarizer, Icy Rock, Heat Rock, Smooth Rock, Damp Rock, Destiny Knot, Luminous Moss, Never-Melt Ice, Wide Lens, Scope Lens, and Zoom Lens.
- Iron Ball, Metal Coat, Throat Spray, Terrain Extender, Medicinal Brew, Moomoo Milk, HP Up, Protein, Iron, Carbos, Calcium, Zinc, PP Up, PP Max, Upgrade, Dubious Disc, and Loaded Dice.
- The following items can now be placed on various surfaces:
- Galarica Wreath, Magnet, Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball.
- The following items can now be placed as blocks and have additional functionality:
@@ -13,9 +13,21 @@
- Galarica Wreath, Cleanse Tag, Spell Tag, Sharp Beak, Covert Cloak, Shell Helmet, and Never-Melt Ice.
- Wearable items can now be equipped by a player by holding it and right-clicking (or rebound use/interact)
- Wearable items that can be placed down are exempt from this behaviour.
- Added custom footstep sounds to the following Pokémon: Arcanine, Wyrdeer, Pidgeot, Corviknight.
- Mint Leaves can now be placed on the ground as Leaf Litter, or in Flower Pots
- Added Oricorio Flowers
- Added Terrain Plants
- Berries can now be placed in Flower Pots
- The evolution tree can now be viewed on the Pokédex, showing a Pokémon's full family line and what's needed to evolve into each stage.
- Added custom sounds to a bunch of items that can be placed as blocks: liquid bottles, pill bottles, powders and dice.
- New Cosmetic Item for Pikachu: Paper
- Burmy changes its cloak after a battle it took part in, based on the biome: Trash Cloak in the Deep Dark, Nether and End, Plant Cloak in lush biomes such as forests, jungles, plains and swamps, and Sandy Cloak in sandy biomes, beaches and caves.
### Fixes
- Medicinal Leeks can now be eaten when they aren't being planted, matching their food properties.
- Sweeping attacks no longer set owned Pokémon on fire (e.g. with Fire Aspect) or knock them back.
- Fixed #updateMovesOnFormChange not properly initializing a form-swapped Pokemon's non-form_change moves.
### TEST
### Pokémon Added
#### Generation 4
- Snover
@@ -66,6 +78,21 @@
- Vileplume
- Bellossom
- Shroomish
- Chespin
- Quilladin
- Chesnaught
- Fennekin
- Braixen
- Delphox
- Froakie
- Frogadier
- Greninja
- Shinx
- Luxio
- Luxray
- Slakoth
- Riolu
- Lucario
### Animation updates for the following Pokémon
- Treecko (New Shoulder Mount!)
@@ -79,17 +106,34 @@
- Gloom
- Vileplume
- Bellossom
- Pichu
- Pikachu
- Raichu (+ Alolan)
- Greninja
- Slakoth
### Changes
- Terrain Seeds can now be planted
- Terrain Seeds are now consumed during PvP and NPC battles
- Glow Item Frames can be crafted using Bright Powder as an alternative to Glow Ink Sacs
- Bright Powder can be used on Signs and Hanging Signs to make text glow, as an alternative to Glow Ink Sacs
- Updated various recipes to display in Recipe Groups within the Recipe Book
- Updated most recipes to display more logically/consistently within the Recipe Book's categories
- Updated the following recipes
- Never-Melt Ice, Focus Sash, Blunder Policy, Weakness Policy, Blank TM
- Make ride rotations less jittery in multiplayer.
- Changes tm shelf discs to use textures instead of tinting and overlays to line up with item display
- Changes Disc Shelf TMs to use textures instead of tinting and overlays to line up with item display
- Blank TM can now be inserted into the Disc Shelf
- Added TM creative tab
- Recall animation now renders ball in hand with the player arm raised.
- Made regional and Vivillon split-evo locations now mutually exclusive
- Item evolutions now unlock **all** locked evolutions whose requirements are met instead of stopping after the first.
- Exceptions being "forced" evolutions which will continue to stop after the first one
- Removed Mega Drain as a TM
- Vivillon's patterns are now viewable as forms with form names and unique Pokedex entries displayed.
- Slowed the speed of Type Gem growth, and revamped their generation to grow in a more crystal-like shape
- PokeSnacks (and other area spawns) will now start the vertical offset checking from the center rather than base coordinate
- This will help PokeSnacks to work inside caves or tighter spaces better
### Fixes
- Correctly grants "They're Minerals!" advancement when planting a type gem
@@ -120,6 +164,15 @@
- Fixed certain Pokémon sounds sometimes being doubled when played at specific times in their animations
- Fixed ball capture beam origin coming from behind the ball.
- Fixed Safari Ball catch rate outside of battle
- Fixed alpha eye (and other) particles not respecting client particle density setting in video options
- Fixed TM-Machine UI not closing when player is moving away from it
- Fixed config category for alpha/shiny chance config fields for fossil machine and honey log slathering to Spawning
- Fixed crashes for addon species with non-Cobblemon namespaces, in evolution, fishing bait and Pokédex lookups.
- Bees now grow Apricorns and the Galarica Nut Bush, which were in the bee growables tag but never handled, and correctly spend their nectar when they do
- Saccharine Leaves can now be bone mealed
- Fixed equipping a stack of items instead of one item of a stack
- Fixed TM stack consumption in TMM screen when player teaches a move to species
- Fixed every Miltank giving mushroom stew, not only mushroom variants
### Developer
- Evolution requirements can now set `pokedexIcon` and `pokedexTooltip` directly in their JSON to control how they're shown on the Pokédex's evolution tree, for example:
@@ -136,6 +189,11 @@
### Molang & Datapacks
- A new `negate` variant for evolution requirements has been added, which will negate (invert) the provided inner condition.
- Added Molang functions for individual Pokédex ids, wherein a subdex is passed in as a string to `dex_caught_count` etc.
- `q.is_standing_on_blocks` now properly checks for non-full blocks like slabs, Mud or Soul Sand
- Added Molang functions to play footstep sounds based on the corresponding surface. These are intended to be used by Pokémon animations.
- Added a `battle_ended` callback, backed by the new `BATTLE_ENDED` event, which fires whenever a battle ends for any reason, alongside a multitude of flags not previously covered by `BATTLE_VICTORY`.
- Added `battle_pokemon` to battle actor structs and `has_faced_opponents` to battle Pokémon structs.
- Added the `cobblemon:form_change/bagworm_cloak/plant_cloak`, `sandy_cloak` and `trash_cloak` biome tags, which control Burmy's cloak after battle.
### Particles
@@ -8,54 +8,42 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.block.SaccharineLeafBlock;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.animal.Bee;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BonemealableBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(targets = "net.minecraft.world.entity.animal.Bee$BeeGrowCropGoal")
public abstract class BeeEntityMixin {
@Unique
private BlockState cobblemon$result = null;
@Inject(method = "tick()V", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/block/BonemealableBlock;performBonemeal(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/util/RandomSource;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V",
shift = At.Shift.BY,
by = 2
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void injectCustomGrowth(CallbackInfo ci, int i, BlockPos blockPos, BlockState blockState, Block block) {
if (block instanceof SaccharineLeafBlock) {
int age = blockState.getValue(SaccharineLeafBlock.Companion.getAGE());
boolean waterlogged = blockState.getValue(BlockStateProperties.WATERLOGGED);
if (age < 2 && !waterlogged) {
this.cobblemon$result = blockState.setValue(SaccharineLeafBlock.Companion.getAGE(), age + 1);
}
}
}
@Shadow(aliases = {"this$0", "field_20373"}) @Final private Bee bee;
// Grows bonemealable blocks vanilla's hardcoded checks miss, returning the state so it handles the rest.
@ModifyVariable(method = "tick", at = @At(value = "LOAD", ordinal = 0), index = 5)
private BlockState applyCustomBlockState(BlockState before) {
if(this.cobblemon$result != null && before == null) {
BlockState result = this.cobblemon$result;
this.cobblemon$result = null;
return result;
private BlockState cobblemon$growBonemealableBlocks(BlockState grownState, @Local(ordinal = 0) BlockState blockState, @Local BlockPos pos) {
if (grownState != null || blockState.is(Blocks.CAVE_VINES) || blockState.is(Blocks.CAVE_VINES_PLANT)) {
return grownState;
}
return before;
if (!(blockState.getBlock() instanceof BonemealableBlock bonemealable)) {
return null;
}
ServerLevel level = (ServerLevel) this.bee.level();
if (!bonemealable.isValidBonemealTarget(level, pos, blockState)) {
return null;
}
bonemealable.performBonemeal(level, this.bee.getRandom(), pos, blockState);
return level.getBlockState(pos);
}
}
@@ -15,6 +15,7 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.mojang.serialization.MapCodec;
import java.util.Optional;
import java.util.function.Supplier;
import net.minecraft.SharedConstants;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.IntTag;
import net.minecraft.resources.ResourceKey;
@@ -45,4 +46,24 @@ public class ChunkStorageMixin {
int curVersion = vanillaFixed.contains(VERSION_KEY) ? vanillaFixed.getInt(VERSION_KEY) : 0;
return DataFixTypes.CHUNK.update(CobblemonSchemas.getDATA_FIXER(), vanillaFixed, curVersion, CobblemonSchemas.DATA_VERSION);
}
// Our update on the same MC version still needs its own fixes so run them here in that case.
@Inject(
method = "upgradeChunkTag(Lnet/minecraft/resources/ResourceKey;Ljava/util/function/Supplier;Lnet/minecraft/nbt/CompoundTag;Ljava/util/Optional;)Lnet/minecraft/nbt/CompoundTag;",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$doChunkFixOnCurrentVersion(
ResourceKey<Level> levelKey,
Supplier<DimensionDataStorage> storage,
CompoundTag chunkData,
Optional<ResourceKey<MapCodec<? extends ChunkGenerator>>> chunkGeneratorKey,
CallbackInfoReturnable<CompoundTag> cir
) {
if (ChunkStorage.getVersion(chunkData) != SharedConstants.getCurrentVersion().getDataVersion().getVersion()) {
return;
}
int curVersion = chunkData.contains(VERSION_KEY) ? chunkData.getInt(VERSION_KEY) : 0;
cir.setReturnValue(DataFixTypes.CHUNK.update(CobblemonSchemas.getDATA_FIXER(), chunkData, curVersion, CobblemonSchemas.DATA_VERSION));
}
}
@@ -35,13 +35,16 @@ import com.cobblemon.mod.common.util.DataKeys;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
@@ -50,6 +53,7 @@ import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
@@ -371,4 +375,33 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
this.cobblemon$rideEyePos = rideEyePos;
}
/**
* Sweeping attacks apply post-attack enchantment effects (e.g. Fire Aspect) to every entity caught
* in the sweep, even if the damage itself was blocked. Skip them for Pokémon immune to the attack.
*/
@WrapOperation(
method = "attack",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/enchantment/EnchantmentHelper;doPostAttackEffects(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;)V")
)
private void cobblemon$skipPostAttackEffectsOnImmunePokemon(ServerLevel level, Entity target, DamageSource source, Operation<Void> original) {
if (target instanceof PokemonEntity pokemonEntity && pokemonEntity.isInvulnerableTo(source)) {
return;
}
original.call(level, target, source);
}
/**
* Sweeping attacks also knock back every entity caught in the sweep regardless of whether it took damage.
*/
@WrapOperation(
method = "attack",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;knockback(DDD)V")
)
private void cobblemon$skipKnockbackOnImmunePokemon(LivingEntity target, double strength, double x, double z, Operation<Void> original, @Local DamageSource source) {
if (target instanceof PokemonEntity pokemonEntity && pokemonEntity.isInvulnerableTo(source)) {
return;
}
original.call(target, strength, x, z);
}
}
@@ -109,4 +109,21 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
"poke_snack",
BlockEntityType.Builder.of(::PokeSnackBlockEntity, CobblemonBlocks.POKE_SNACK, CobblemonBlocks.POKE_CAKE).build(null)
)
@JvmField
val TERRAIN_PLANT: BlockEntityType<TerrainPlantBlockEntity> = this.create(
"terrain_plant",
BlockEntityType.Builder.of(::TerrainPlantBlockEntity,
CobblemonBlocks.VOLTACONIA,
CobblemonBlocks.LUCIBELL,
CobblemonBlocks.VERDROOT
).build(null)
)
@JvmField
val MISTLEAF_FLOWER: BlockEntityType<MistleafFlowerBlockEntity> = this.create(
"mistleaf",
BlockEntityType.Builder.of(::MistleafFlowerBlockEntity,
CobblemonBlocks.MISTLEAF
).build(null)
)
}
@@ -16,8 +16,7 @@ import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
import com.cobblemon.mod.common.block.campfirepot.CampfirePotBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.decor.ActivatableDecorationBlock
import com.cobblemon.mod.common.block.decor.RingTargetBlock
import com.cobblemon.mod.common.block.decor.*
import com.cobblemon.mod.common.block.general.BaleBlock
import com.cobblemon.mod.common.block.general.HorizontalRotationCarpetBlock
import com.cobblemon.mod.common.block.general.HorizontalRotationalBlock
@@ -28,6 +27,7 @@ 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 com.cobblemon.mod.common.block.tmmachine.TMMachineBlock
import com.cobblemon.mod.common.block.general.MintLitterBlock
import com.cobblemon.mod.common.mixin.invoker.BlocksInvoker
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.FireBlockInvoker
@@ -653,6 +653,10 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val CHIPPED_POT = create("chipped_pot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEAPOT))
@JvmField
val CRACKED_POT = create("cracked_pot", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.DECORATED_POT).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.TEAPOT))
@JvmField
val ELECTIRIZER = create("electirizer", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.IZER))
@JvmField
val MAGMARIZER = create("magmarizer", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.METAL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.IZER))
@JvmField
val SACHET = create("sachet", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOL).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@@ -662,6 +666,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val QUICK_POWDER = create("quick_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_POWDER_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val BRIGHT_POWDER = create("bright_powder", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_POWDER_SOUNDS).mapColor(MapColor.NONE).noOcclusion().lightLevel{3}, DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val SOFT_SAND = create("soft_sand", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_POWDER_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), DecorativeItemBlock.DecorativeItemBlockType.POUCH))
@JvmField
val NEVER_MELT_ICE = create("never_melt_ice", DecorativeItemBlock(BlockBehaviour.Properties.of().sound(SoundType.GLASS).mapColor(MapColor.NONE).noOcclusion().friction(0.989F), DecorativeItemBlock.DecorativeItemBlockType.NEVERMELT))
@@ -703,6 +709,12 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val THROAT_SPRAY = create("throat_spray", StackableItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_BOTTLE_LIQUID_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.THROAT_SPRAY))
@JvmField
val TERRAIN_EXTENDER = create("terrain_extender", StackableItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_METAL_CAN_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.EXTENDER))
@JvmField
val MOOMOO_MILK = create("moomoo_milk", StackableItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_JAR_GLASS_LIQUID_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.GLASS_BOTTLE))
@JvmField
val MEDICINAL_BREW = create("medicinal_brew", StackableItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_JAR_GLASS_LIQUID_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.GLASS_BOTTLE))
@JvmField
val FULL_HEAL = create("full_heal", StackableItemBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.ITEM_BLOCK_BOTTLE_LIQUID_SOUNDS).mapColor(MapColor.NONE).noOcclusion(), StackableItemBlock.StackableItemBlockType.STATUS_RESTORE))
@@ -857,6 +869,64 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val POTTED_SACCHARINE_SAPLING = this.create("potted_saccharine_sapling", BlocksInvoker.createFlowerPotBlock(SACCHARINE_SAPLING))
@JvmField
val RED_MINT_LEAF_LITTER = this.mintLitter("red_mint_leaf_litter", MapColor.COLOR_RED)
@JvmField
val POTTED_RED_MINT = this.pottedPlant("potted_red_mint", RED_MINT_LEAF_LITTER)
@JvmField
val BLUE_MINT_LEAF_LITTER = this.mintLitter("blue_mint_leaf_litter", MapColor.COLOR_BLUE)
@JvmField
val POTTED_BLUE_MINT = this.pottedPlant("potted_blue_mint", BLUE_MINT_LEAF_LITTER)
@JvmField
val CYAN_MINT_LEAF_LITTER = this.mintLitter("cyan_mint_leaf_litter", MapColor.COLOR_CYAN)
@JvmField
val POTTED_CYAN_MINT = this.pottedPlant("potted_cyan_mint", CYAN_MINT_LEAF_LITTER)
@JvmField
val PINK_MINT_LEAF_LITTER = this.mintLitter("pink_mint_leaf_litter", MapColor.COLOR_PINK)
@JvmField
val POTTED_PINK_MINT = this.pottedPlant("potted_pink_mint", PINK_MINT_LEAF_LITTER)
@JvmField
val GREEN_MINT_LEAF_LITTER = this.mintLitter("green_mint_leaf_litter", MapColor.COLOR_GREEN)
@JvmField
val POTTED_GREEN_MINT = this.pottedPlant("potted_green_mint", GREEN_MINT_LEAF_LITTER)
@JvmField
val WHITE_MINT_LEAF_LITTER = this.mintLitter("white_mint_leaf_litter", MapColor.SNOW)
@JvmField
val POTTED_WHITE_MINT = this.pottedPlant("potted_white_mint", WHITE_MINT_LEAF_LITTER)
@JvmField
val LOBAILA = this.create("lobaila", LobailaFlowerBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().instabreak().sound(SoundType.GRASS).offsetType(BlockBehaviour.OffsetType.XZ).ignitedByLava().pushReaction(PushReaction.DESTROY)))
@JvmField
val POMOHANA = this.create("pomohana", PomohanaFlowerBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().instabreak().sound(SoundType.GRASS).ignitedByLava().pushReaction(PushReaction.DESTROY)))
@JvmField
val PAUVILLEA = this.create("pauvillea",PauvilleaFlowerBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().sound(SoundType.GRASS).instabreak().ignitedByLava().pushReaction(PushReaction.DESTROY)))
@JvmField
val WISTENSU = this.create("wistensu", WistensuFlowerHeadBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().sound(SoundType.GRASS).instabreak().ignitedByLava().pushReaction(PushReaction.DESTROY).lightLevel{11}))
@JvmField
val WISTENSU_VINE = this.create("wistensu_vine", WistensuFlowerVineBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().sound(SoundType.GRASS).instabreak().ignitedByLava().pushReaction(PushReaction.DESTROY)))
@JvmField
val ELECTRIC_SEED = this.terrainSeed("electric_seed", TerrainSeedBlock.TerrainSeedType.ELECTRIC)
@JvmField
val PSYCHIC_SEED = this.terrainSeed("psychic_seed", TerrainSeedBlock.TerrainSeedType.PSYCHIC)
@JvmField
val MISTY_SEED = this.terrainSeed("misty_seed", TerrainSeedBlock.TerrainSeedType.MISTY)
@JvmField
val GRASSY_SEED = this.terrainSeed("grassy_seed", TerrainSeedBlock.TerrainSeedType.GRASSY)
@JvmField
val VOLTACONIA = this.terrainPlant("voltaconia") { state -> if (state.getValue(TerrainPlantBlock.GLOWING)) 8 else 0 }
@JvmField
val VERDROOT = this.terrainPlant("verdroot") { state -> if (state.getValue(TerrainPlantBlock.GLOWING)) 5 else 0 }
@JvmField
val LUCIBELL = this.terrainPlant("lucibell") { state -> if (state.getValue(TerrainPlantBlock.GLOWING)) 8 else 0 }
@JvmField
val MISTLEAF = this.create(
"mistleaf",
MistleafFlowerBlock {
if ((it.getValue(MistleafFlowerBlock.GLOWING) >= 1)) it.getValue(MistleafFlowerBlock.GLOWING) + 2 else 0
}
)
@JvmField
val HEARTY_GRAIN_BALE = this.create("hearty_grain_bale", BaleBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).instrument(NoteBlockInstrument.BANJO).strength(0.5F).sound(CobblemonSounds.HEARTY_GRAIN_BALE_SOUNDS)))
@JvmField
@@ -1033,6 +1103,147 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val YACHE_BERRY = this.berryBlock("yache")
//val BINDING_SOIL = this.create("binding_soil", BindingSoilBlock(BlockBehaviour.Properties.of()))
@JvmField
val POTTED_AGUAV_BERRY = this.create("potted_aguav_berry", BlocksInvoker.createFlowerPotBlock(AGUAV_BERRY))
@JvmField
val POTTED_APICOT_BERRY = this.create("potted_apicot_berry", BlocksInvoker.createFlowerPotBlock(APICOT_BERRY))
@JvmField
val POTTED_ASPEAR_BERRY = this.create("potted_aspear_berry", BlocksInvoker.createFlowerPotBlock(ASPEAR_BERRY))
@JvmField
val POTTED_BABIRI_BERRY = this.create("potted_babiri_berry", BlocksInvoker.createFlowerPotBlock(BABIRI_BERRY))
@JvmField
val POTTED_BELUE_BERRY = this.create("potted_belue_berry", BlocksInvoker.createFlowerPotBlock(BELUE_BERRY))
@JvmField
val POTTED_BLUK_BERRY = this.create("potted_bluk_berry", BlocksInvoker.createFlowerPotBlock(BLUK_BERRY))
@JvmField
val POTTED_CHARTI_BERRY = this.create("potted_charti_berry", BlocksInvoker.createFlowerPotBlock(CHARTI_BERRY))
@JvmField
val POTTED_CHERI_BERRY = this.create("potted_cheri_berry", BlocksInvoker.createFlowerPotBlock(CHERI_BERRY))
@JvmField
val POTTED_CHESTO_BERRY = this.create("potted_chesto_berry", BlocksInvoker.createFlowerPotBlock(CHESTO_BERRY))
@JvmField
val POTTED_CHILAN_BERRY = this.create("potted_chilan_berry", BlocksInvoker.createFlowerPotBlock(CHILAN_BERRY))
@JvmField
val POTTED_CHOPLE_BERRY = this.create("potted_chople_berry", BlocksInvoker.createFlowerPotBlock(CHOPLE_BERRY))
@JvmField
val POTTED_COBA_BERRY = this.create("potted_coba_berry", BlocksInvoker.createFlowerPotBlock(COBA_BERRY))
@JvmField
val POTTED_COLBUR_BERRY = this.create("potted_colbur_berry", BlocksInvoker.createFlowerPotBlock(COLBUR_BERRY))
@JvmField
val POTTED_CORNN_BERRY = this.create("potted_cornn_berry", BlocksInvoker.createFlowerPotBlock(CORNN_BERRY))
@JvmField
val POTTED_CUSTAP_BERRY = this.create("potted_custap_berry", BlocksInvoker.createFlowerPotBlock(CUSTAP_BERRY))
@JvmField
val POTTED_DURIN_BERRY = this.create("potted_durin_berry", BlocksInvoker.createFlowerPotBlock(DURIN_BERRY))
@JvmField
val POTTED_EGGANT_BERRY = this.create("potted_eggant_berry", BlocksInvoker.createFlowerPotBlock(EGGANT_BERRY))
@JvmField
val POTTED_ENIGMA_BERRY = this.create("potted_enigma_berry", BlocksInvoker.createFlowerPotBlock(ENIGMA_BERRY))
@JvmField
val POTTED_FIGY_BERRY = this.create("potted_figy_berry", BlocksInvoker.createFlowerPotBlock(FIGY_BERRY))
@JvmField
val POTTED_GANLON_BERRY = this.create("potted_ganlon_berry", BlocksInvoker.createFlowerPotBlock(GANLON_BERRY))
@JvmField
val POTTED_GREPA_BERRY = this.create("potted_grepa_berry", BlocksInvoker.createFlowerPotBlock(GREPA_BERRY))
@JvmField
val POTTED_HABAN_BERRY = this.create("potted_haban_berry", BlocksInvoker.createFlowerPotBlock(HABAN_BERRY))
@JvmField
val POTTED_HONDEW_BERRY = this.create("potted_hondew_berry", BlocksInvoker.createFlowerPotBlock(HONDEW_BERRY))
@JvmField
val POTTED_HOPO_BERRY = this.create("potted_hopo_berry", BlocksInvoker.createFlowerPotBlock(HOPO_BERRY))
@JvmField
val POTTED_IAPAPA_BERRY = this.create("potted_iapapa_berry", BlocksInvoker.createFlowerPotBlock(IAPAPA_BERRY))
@JvmField
val POTTED_JABOCA_BERRY = this.create("potted_jaboca_berry", BlocksInvoker.createFlowerPotBlock(JABOCA_BERRY))
@JvmField
val POTTED_KASIB_BERRY = this.create("potted_kasib_berry", BlocksInvoker.createFlowerPotBlock(KASIB_BERRY))
@JvmField
val POTTED_KEBIA_BERRY = this.create("potted_kebia_berry", BlocksInvoker.createFlowerPotBlock(KEBIA_BERRY))
@JvmField
val POTTED_KEE_BERRY = this.create("potted_kee_berry", BlocksInvoker.createFlowerPotBlock(KEE_BERRY))
@JvmField
val POTTED_KELPSY_BERRY = this.create("potted_kelpsy_berry", BlocksInvoker.createFlowerPotBlock(KELPSY_BERRY))
@JvmField
val POTTED_LANSAT_BERRY = this.create("potted_lansat_berry", BlocksInvoker.createFlowerPotBlock(LANSAT_BERRY))
@JvmField
val POTTED_LEPPA_BERRY = this.create("potted_leppa_berry", BlocksInvoker.createFlowerPotBlock(LEPPA_BERRY))
@JvmField
val POTTED_LIECHI_BERRY = this.create("potted_liechi_berry", BlocksInvoker.createFlowerPotBlock(LIECHI_BERRY))
@JvmField
val POTTED_LUM_BERRY = this.create("potted_lum_berry", BlocksInvoker.createFlowerPotBlock(LUM_BERRY))
@JvmField
val POTTED_MAGO_BERRY = this.create("potted_mago_berry", BlocksInvoker.createFlowerPotBlock(MAGO_BERRY))
@JvmField
val POTTED_MAGOST_BERRY = this.create("potted_magost_berry", BlocksInvoker.createFlowerPotBlock(MAGOST_BERRY))
@JvmField
val POTTED_MARANGA_BERRY = this.create("potted_maranga_berry", BlocksInvoker.createFlowerPotBlock(MARANGA_BERRY))
@JvmField
val POTTED_MICLE_BERRY = this.create("potted_micle_berry", BlocksInvoker.createFlowerPotBlock(MICLE_BERRY))
@JvmField
val POTTED_NANAB_BERRY = this.create("potted_nanab_berry", BlocksInvoker.createFlowerPotBlock(NANAB_BERRY))
@JvmField
val POTTED_NOMEL_BERRY = this.create("potted_nomel_berry", BlocksInvoker.createFlowerPotBlock(NOMEL_BERRY))
@JvmField
val POTTED_OCCA_BERRY = this.create("potted_occa_berry", BlocksInvoker.createFlowerPotBlock(OCCA_BERRY))
@JvmField
val POTTED_ORAN_BERRY = this.create("potted_oran_berry", BlocksInvoker.createFlowerPotBlock(ORAN_BERRY))
@JvmField
val POTTED_PAMTRE_BERRY = this.create("potted_pamtre_berry", BlocksInvoker.createFlowerPotBlock(PAMTRE_BERRY))
@JvmField
val POTTED_PASSHO_BERRY = this.create("potted_passho_berry", BlocksInvoker.createFlowerPotBlock(PASSHO_BERRY))
@JvmField
val POTTED_PAYAPA_BERRY = this.create("potted_payapa_berry", BlocksInvoker.createFlowerPotBlock(PAYAPA_BERRY))
@JvmField
val POTTED_PECHA_BERRY = this.create("potted_pecha_berry", BlocksInvoker.createFlowerPotBlock(PECHA_BERRY))
@JvmField
val POTTED_PERSIM_BERRY = this.create("potted_persim_berry", BlocksInvoker.createFlowerPotBlock(PERSIM_BERRY))
@JvmField
val POTTED_PETAYA_BERRY = this.create("potted_petaya_berry", BlocksInvoker.createFlowerPotBlock(PETAYA_BERRY))
@JvmField
val POTTED_PINAP_BERRY = this.create("potted_pinap_berry", BlocksInvoker.createFlowerPotBlock(PINAP_BERRY))
@JvmField
val POTTED_POMEG_BERRY = this.create("potted_pomeg_berry", BlocksInvoker.createFlowerPotBlock(POMEG_BERRY))
@JvmField
val POTTED_QUALOT_BERRY = this.create("potted_qualot_berry", BlocksInvoker.createFlowerPotBlock(QUALOT_BERRY))
@JvmField
val POTTED_RABUTA_BERRY = this.create("potted_rabuta_berry", BlocksInvoker.createFlowerPotBlock(RABUTA_BERRY))
@JvmField
val POTTED_RAWST_BERRY = this.create("potted_rawst_berry", BlocksInvoker.createFlowerPotBlock(RAWST_BERRY))
@JvmField
val POTTED_RAZZ_BERRY = this.create("potted_razz_berry", BlocksInvoker.createFlowerPotBlock(RAZZ_BERRY))
@JvmField
val POTTED_RINDO_BERRY = this.create("potted_rindo_berry", BlocksInvoker.createFlowerPotBlock(RINDO_BERRY))
@JvmField
val POTTED_ROSELI_BERRY = this.create("potted_roseli_berry", BlocksInvoker.createFlowerPotBlock(ROSELI_BERRY))
@JvmField
val POTTED_ROWAP_BERRY = this.create("potted_rowap_berry", BlocksInvoker.createFlowerPotBlock(ROWAP_BERRY))
@JvmField
val POTTED_SALAC_BERRY = this.create("potted_salac_berry", BlocksInvoker.createFlowerPotBlock(SALAC_BERRY))
@JvmField
val POTTED_SHUCA_BERRY = this.create("potted_shuca_berry", BlocksInvoker.createFlowerPotBlock(SHUCA_BERRY))
@JvmField
val POTTED_SITRUS_BERRY = this.create("potted_sitrus_berry", BlocksInvoker.createFlowerPotBlock(SITRUS_BERRY))
@JvmField
val POTTED_SPELON_BERRY = this.create("potted_spelon_berry", BlocksInvoker.createFlowerPotBlock(SPELON_BERRY))
@JvmField
val POTTED_STARF_BERRY = this.create("potted_starf_berry", BlocksInvoker.createFlowerPotBlock(STARF_BERRY))
@JvmField
val POTTED_TAMATO_BERRY = this.create("potted_tamato_berry", BlocksInvoker.createFlowerPotBlock(TAMATO_BERRY))
@JvmField
val POTTED_TANGA_BERRY = this.create("potted_tanga_berry", BlocksInvoker.createFlowerPotBlock(TANGA_BERRY))
@JvmField
val POTTED_TOUGA_BERRY = this.create("potted_touga_berry", BlocksInvoker.createFlowerPotBlock(TOUGA_BERRY))
@JvmField
val POTTED_WACAN_BERRY = this.create("potted_wacan_berry", BlocksInvoker.createFlowerPotBlock(WACAN_BERRY))
@JvmField
val POTTED_WATMEL_BERRY = this.create("potted_watmel_berry", BlocksInvoker.createFlowerPotBlock(WATMEL_BERRY))
@JvmField
val POTTED_WEPEAR_BERRY = this.create("potted_wepear_berry", BlocksInvoker.createFlowerPotBlock(WEPEAR_BERRY))
@JvmField
val POTTED_WIKI_BERRY = this.create("potted_wiki_berry", BlocksInvoker.createFlowerPotBlock(WIKI_BERRY))
@JvmField
val POTTED_YACHE_BERRY = this.create("potted_yache_berry", BlocksInvoker.createFlowerPotBlock(YACHE_BERRY))
init {
/**
* Makes all blocks in array flammable by adding them to FireBlock's flammableRegistry.
@@ -1134,4 +1345,48 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
}
fun typeGemClusters() = typeGemClusters.toMap()
private fun pottedPlant(name: String, flower: Block) = this.create(name, BlocksInvoker.createFlowerPotBlock(flower))
private fun mintLitter(name: String, color: MapColor) = this.create(
name,
MintLitterBlock(
BlockBehaviour.Properties.of()
.sound(CobblemonSounds.MINT_SOUNDS)
.mapColor(color)
.noOcclusion()
.noCollission()
.pushReaction(PushReaction.DESTROY)
)
)
private fun terrainSeed(name: String, type: TerrainSeedBlock.TerrainSeedType) = this.create(
name,
TerrainSeedBlock(
type,
BlockBehaviour.Properties.of()
.pushReaction(PushReaction.DESTROY)
.ignitedByLava()
.mapColor(MapColor.PLANT)
.offsetType(BlockBehaviour.OffsetType.XZ)
.noCollission()
.randomTicks()
.instabreak()
)
)
private fun terrainPlant(name: String, lightLevel: (BlockState) -> Int) = this.create(
name,
TerrainPlantBlock(
BlockBehaviour.Properties.of()
.mapColor(MapColor.PLANT)
.noCollission()
.instabreak()
.sound(SoundType.GRASS)
.offsetType(BlockBehaviour.OffsetType.XZ)
.ignitedByLava()
.pushReaction(PushReaction.DESTROY)
.lightLevel(lightLevel)
)
)
}
@@ -477,8 +477,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val DUBIOUS_DISC = itemNameBlockItem("dubious_disc", CobblemonBlocks.DUBIOUS_DISC)
@JvmField val DEEP_SEA_SCALE = noSettingsItem("deep_sea_scale")
@JvmField val DEEP_SEA_TOOTH = noSettingsItem("deep_sea_tooth")
@JvmField val ELECTIRIZER = noSettingsItem("electirizer")
@JvmField val MAGMARIZER = noSettingsItem("magmarizer")
@JvmField val ELECTIRIZER = itemNameBlockItem("electirizer", CobblemonBlocks.ELECTIRIZER)
@JvmField val MAGMARIZER = itemNameBlockItem("magmarizer", CobblemonBlocks.MAGMARIZER)
@JvmField val OVAL_STONE = noSettingsItem("oval_stone")
@JvmField val PROTECTOR = noSettingsItem("protector")
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
@@ -711,7 +711,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val PEP_UP_FLOWER = compostableBlockItem("pep_up_flower", CobblemonBlocks.PEP_UP_FLOWER)
@JvmField
val MEDICINAL_BREW = noSettingsItem("medicinal_brew")
val MEDICINAL_BREW = itemNameBlockItem("medicinal_brew", CobblemonBlocks.MEDICINAL_BREW)
@JvmField
val REMEDY = compostableItem("remedy", RemedyItem(RemedyItem.NORMAL), 0.65f)
@JvmField
@@ -719,7 +719,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SUPERB_REMEDY = compostableItem("superb_remedy", RemedyItem(RemedyItem.SUPERB), 1f)
@JvmField
val MOOMOO_MILK = create("moomoo_milk", MoomooMilk(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
val MOOMOO_MILK = create("moomoo_milk", MoomooMilk(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16)), CobblemonBlocks.MOOMOO_MILK))
@JvmField
val POTION = create("potion", PotionItem(PotionType.POTION, CobblemonBlocks.POTION))
@@ -748,27 +748,27 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val RED_MINT_SEEDS = mintSeed("red", MintType.RED.getCropBlock())
@JvmField
val RED_MINT_LEAF = mintLeaf("red", MintLeafItem(MintType.RED))
val RED_MINT_LEAF = compostableItemNameBlockItem("red_mint_leaf", CobblemonBlocks.RED_MINT_LEAF_LITTER, 0.50f)
@JvmField
val BLUE_MINT_SEEDS = mintSeed("blue", MintType.BLUE.getCropBlock())
@JvmField
val BLUE_MINT_LEAF = mintLeaf("blue", MintLeafItem(MintType.BLUE))
val BLUE_MINT_LEAF = compostableItemNameBlockItem("blue_mint_leaf", CobblemonBlocks.BLUE_MINT_LEAF_LITTER, 0.50f)
@JvmField
val CYAN_MINT_SEEDS = mintSeed("cyan", MintType.CYAN.getCropBlock())
@JvmField
val CYAN_MINT_LEAF = mintLeaf("cyan", MintLeafItem(MintType.CYAN))
val CYAN_MINT_LEAF = compostableItemNameBlockItem("cyan_mint_leaf", CobblemonBlocks.CYAN_MINT_LEAF_LITTER, 0.50f)
@JvmField
val PINK_MINT_SEEDS = mintSeed("pink", MintType.PINK.getCropBlock())
@JvmField
val PINK_MINT_LEAF = mintLeaf("pink", MintLeafItem(MintType.PINK))
val PINK_MINT_LEAF = compostableItemNameBlockItem("pink_mint_leaf", CobblemonBlocks.PINK_MINT_LEAF_LITTER, 0.50f)
@JvmField
val GREEN_MINT_SEEDS = mintSeed("green", MintType.GREEN.getCropBlock())
@JvmField
val GREEN_MINT_LEAF = mintLeaf("green", MintLeafItem(MintType.GREEN))
val GREEN_MINT_LEAF = compostableItemNameBlockItem("green_mint_leaf", CobblemonBlocks.GREEN_MINT_LEAF_LITTER, 0.50f)
@JvmField
val WHITE_MINT_SEEDS = mintSeed("white", MintType.WHITE.getCropBlock())
@JvmField
val WHITE_MINT_LEAF = mintLeaf("white", MintLeafItem(MintType.WHITE))
val WHITE_MINT_LEAF = compostableItemNameBlockItem("white_mint_leaf", CobblemonBlocks.WHITE_MINT_LEAF_LITTER, 0.50f)
val mints = mutableMapOf<String, MintItem>()
@@ -969,7 +969,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val EJECT_PACK = heldItem("eject_pack")
@JvmField
val ELECTRIC_SEED = heldItem("electric_seed")
val ELECTRIC_SEED = itemNameBlockItem("electric_seed", CobblemonBlocks.ELECTRIC_SEED)
@JvmField
val EVERSTONE = heldItem("everstone")
@JvmField
@@ -985,7 +985,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val FOCUS_SASH = heldItem("focus_sash")
@JvmField
val GRASSY_SEED = heldItem("grassy_seed")
val GRASSY_SEED = itemNameBlockItem("grassy_seed", CobblemonBlocks.GRASSY_SEED)
@JvmField
val GRIP_CLAW = heldItem("grip_claw")
@JvmField
@@ -1033,7 +1033,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val POWER_WEIGHT = heldItem("power_weight")
@JvmField
val PSYCHIC_SEED = heldItem("psychic_seed")
val PSYCHIC_SEED = itemNameBlockItem("psychic_seed", CobblemonBlocks.PSYCHIC_SEED)
@JvmField
val PROTECTIVE_PADS = heldItem("protective_pads")
@JvmField
@@ -1057,7 +1057,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val SILVER_POWDER = heldItem("silver_powder")
@JvmField
val SOFT_SAND = heldItem("soft_sand")
val SOFT_SAND = itemNameBlockItem("soft_sand", CobblemonBlocks.SOFT_SAND)
@JvmField
val SMOKE_BALL = itemNameBlockItem("smoke_ball", CobblemonBlocks.SMOKE_BALL)
@JvmField
@@ -1065,7 +1065,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val STICKY_BARB = heldItem("sticky_barb")
@JvmField
val TERRAIN_EXTENDER = heldItem("terrain_extender")
val TERRAIN_EXTENDER = itemNameBlockItem("terrain_extender", CobblemonBlocks.TERRAIN_EXTENDER)
@JvmField
val THROAT_SPRAY = itemNameBlockItem("throat_spray", CobblemonBlocks.THROAT_SPRAY)
@JvmField
@@ -1085,13 +1085,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val MIRROR_HERB = compostableHeldItem("mirror_herb", null, 0.85F)
@JvmField
val MISTY_SEED = heldItem("misty_seed")
val MISTY_SEED = itemNameBlockItem("misty_seed", CobblemonBlocks.MISTY_SEED)
@JvmField
val POWER_HERB = compostableHeldItem("power_herb", null, 0.85F)
@JvmField
val WHITE_HERB = compostableHeldItem("white_herb", null, 0.85F)
@JvmField
val BRIGHT_POWDER = itemNameBlockItem("bright_powder", CobblemonBlocks.BRIGHT_POWDER)
val BRIGHT_POWDER = glowItem("bright_powder", CobblemonBlocks.BRIGHT_POWDER)
@JvmField
val METAL_POWDER = itemNameBlockItem("metal_powder", CobblemonBlocks.METAL_POWDER)
@JvmField
@@ -1558,6 +1558,25 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
//@JvmField
//val BINDING_SOIL = blockItem("binding_soil", CobblemonBlocks.BINDING_SOIL)
// Plants, Flora, and Flowers
@JvmField
val LOBAILA = compostableBlockItem("lobaila", CobblemonBlocks.LOBAILA, 0.65f)
@JvmField
val POMOHANA = compostableBlockItem("pomohana", CobblemonBlocks.POMOHANA, 0.3f)
@JvmField
val PAUVILLEA = compostableBlockItem("pauvillea", CobblemonBlocks.PAUVILLEA, 0.65f)
@JvmField
val WISTENSU = compostableBlockItem("wistensu", CobblemonBlocks.WISTENSU, 0.5f)
@JvmField
val VOLTACONIA = compostableBlockItem("voltaconia", CobblemonBlocks.VOLTACONIA, 0.85f)
@JvmField
val VERDROOT = compostableBlockItem("verdroot", CobblemonBlocks.VERDROOT, 0.85f)
@JvmField
val MISTLEAF = compostableBlockItem("mistleaf", CobblemonBlocks.MISTLEAF, 0.85f)
@JvmField
val LUCIBELL = compostableBlockItem("lucibell", CobblemonBlocks.LUCIBELL, 0.85f)
private fun blockItem(name: String, block: Block, rarity: Rarity = Rarity.COMMON): BlockItem = this.create(name, BlockItem(block, Item.Properties().rarity(rarity)))
private fun itemNameBlockItem(name: String, block: Block, rarity: Rarity = Rarity.COMMON): ItemNameBlockItem = this.create(name, ItemNameBlockItem(block, Item.Properties().rarity(rarity)))
@@ -1760,4 +1779,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
return CobblemonItem(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
}
private fun glowItem(name: String, block: Block): GlowItem = this.create(name, GlowItem(block, Item.Properties()))
}
@@ -148,6 +148,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val MONITOR_GLITCHING = this.create("block.monitor.glitching")
@JvmField
val BRIGHT_POWDER_USE = this.create("block.bright_powder.use")
@JvmField
val FOSSIL_MACHINE_ACTIVATE = this.create("block.fossil_machine.activate")
@JvmField
@@ -717,5 +720,35 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
ITEM_BLOCK_DICE_STEP
)
@JvmField
val ITEM_BLOCK_METAL_CAN_PLACE = this.create("block.item_block.metal_can.place")
@JvmField
val ITEM_BLOCK_METAL_CAN_BREAK = this.create("block.item_block.metal_can.break")
@JvmField
val ITEM_BLOCK_METAL_CAN_STEP = this.create("block.item_block.metal_can.step")
@JvmField
val ITEM_BLOCK_METAL_CAN_SOUNDS = SoundType(1f, 1.1f,
ITEM_BLOCK_METAL_CAN_BREAK,
ITEM_BLOCK_METAL_CAN_STEP,
ITEM_BLOCK_METAL_CAN_PLACE,
ITEM_BLOCK_METAL_CAN_STEP,
ITEM_BLOCK_METAL_CAN_STEP
)
@JvmField
val ITEM_BLOCK_JAR_GLASS_LIQUID_PLACE = this.create("block.item_block.jar_glass_liquid.place")
@JvmField
val ITEM_BLOCK_JAR_GLASS_LIQUID_BREAK = this.create("block.item_block.jar_glass_liquid.break")
@JvmField
val ITEM_BLOCK_JAR_GLASS_LIQUID_STEP = this.create("block.item_block.jar_glass_liquid.step")
@JvmField
val ITEM_BLOCK_JAR_GLASS_LIQUID_SOUNDS = SoundType(1f, 1.1f,
ITEM_BLOCK_JAR_GLASS_LIQUID_BREAK,
ITEM_BLOCK_JAR_GLASS_LIQUID_STEP,
ITEM_BLOCK_JAR_GLASS_LIQUID_PLACE,
ITEM_BLOCK_JAR_GLASS_LIQUID_STEP,
ITEM_BLOCK_JAR_GLASS_LIQUID_STEP
)
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.createVariableRangeEvent(cobblemonResource(name)))
}
@@ -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.api.battles.model
/**
* How a [PokemonBattle] came to an end.
*/
enum class BattleEndResult {
/** One side defeated the other. */
VICTORY,
/** A wild Pokémon was captured, ending the battle. */
CAPTURE,
/** An actor forfeited, giving the victory to the other side. */
FORFEIT,
/** A player fled from a wild Pokémon. */
FLED,
/** The battle was stopped without a winner, such as by a command, a player disconnecting or an error. */
STOPPED
}
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.battles.BattleEndedEvent
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
import com.cobblemon.mod.common.api.events.battles.BattleFleeAttemptEvent
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
@@ -124,6 +125,12 @@ open class PokemonBattle(
var winners = listOf<BattleActor>()
var losers = listOf<BattleActor>()
var ended = false
/** How the battle ended, or null if it hasn't ended yet. */
var endResult: BattleEndResult? = null
/** The actor that forfeited the battle, if any. */
var forfeitedBy: BattleActor? = null
/** Whether a player fled from the battle. */
var fled = false
// TEMP battle showcase stuff
var announcingRules = false
var turn: Int = 0
@@ -251,6 +258,14 @@ open class PokemonBattle(
fun end() {
ended = true
val result = when {
winners.isNotEmpty() && showdownMessages.any { "capture" in it } -> BattleEndResult.CAPTURE
winners.isNotEmpty() && forfeitedBy != null -> BattleEndResult.FORFEIT
winners.isNotEmpty() -> BattleEndResult.VICTORY
fled -> BattleEndResult.FLED
else -> BattleEndResult.STOPPED
}
endResult = result
val awardToFainted = Cobblemon.config.awardExperienceToFaintedPokemon
val awardOnLoss = Cobblemon.config.awardExperienceOnBattleLoss
this.actors.forEach { actor ->
@@ -332,6 +347,7 @@ open class PokemonBattle(
}
}
}
CobblemonEvents.BATTLE_ENDED.post(BattleEndedEvent(this, result, forfeitedBy.takeIf { result == BattleEndResult.FORFEIT }))
sendUpdate(BattleEndPacket())
BattleRegistry.closeBattle(this)
}
@@ -502,6 +518,7 @@ open class PokemonBattle(
.forEach{it.pokemon.heal()}
CobblemonEvents.BATTLE_FLED.post(BattleFledEvent(this, actors.asSequence().filterIsInstance<PlayerBattleActor>().iterator().next()))
actors.filterIsInstance<EntityBackedBattleActor<*>>().mapNotNull { it.entity }.forEach { it.sendSystemMessage(battleLang("flee").yellow()) }
fled = true
stop()
}
}
@@ -539,6 +556,7 @@ open class PokemonBattle(
private fun checkForfeit(): Boolean {
val forfeit = actors.find { it.responses.any { it is ForfeitActionResponse } }
return forfeit?.let {
forfeitedBy = it
this.dispatchWaiting { this.broadcastChatMessage(battleLang("forfeit", it.getName()).red()) }
writeShowdownAction(">forcelose ${it.showdownId}")
true
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.events.battles.BattleFaintedEvent
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
import com.cobblemon.mod.common.api.events.battles.BattleFleeAttemptEvent
import com.cobblemon.mod.common.api.events.battles.BattleStartedEvent
import com.cobblemon.mod.common.api.events.battles.BattleEndedEvent
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
import com.cobblemon.mod.common.api.events.battles.instruction.FormeChangeEvent
import com.cobblemon.mod.common.api.events.battles.instruction.MegaEvolutionEvent
@@ -139,6 +140,9 @@ object CobblemonEvents {
@JvmField
val BATTLE_FAINTED = EventObservable<BattleFaintedEvent>()
@JvmField
val BATTLE_ENDED = EventObservable<BattleEndedEvent>()
// instructions
@JvmField
val MEGA_EVOLUTION = EventObservable<MegaEvolutionEvent>()
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.battles
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.battles.model.BattleEndResult
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.battles.model.actor.ActorType
import com.cobblemon.mod.common.util.asArrayValue
/**
* Event fired whenever a [PokemonBattle] ends, regardless of how it ended (victory, fleeing, being stopped, etc).
*
* [PokemonBattle.winners] and [PokemonBattle.losers] are only populated if the [result] has a winner,
* that is [BattleEndResult.VICTORY], [BattleEndResult.CAPTURE] or [BattleEndResult.FORFEIT].
*
* @param result How the battle ended.
* @param forfeitedBy The actor that forfeited, if the [result] is [BattleEndResult.FORFEIT].
*/
data class BattleEndedEvent(
override val battle: PokemonBattle,
val result: BattleEndResult,
val forfeitedBy: BattleActor?
) : BattleEvent {
/** Whether one side won the battle, which includes captures and forfeits. */
val hasWinner = battle.winners.isNotEmpty()
val wasVictory = result == BattleEndResult.VICTORY
val wasCapture = result == BattleEndResult.CAPTURE
val wasForfeit = result == BattleEndResult.FORFEIT
val wasFled = result == BattleEndResult.FLED
val wasStopped = result == BattleEndResult.STOPPED
/** Whether the battle was between players and wild Pokémon. */
val isPvW = battle.isPvW
/** Whether the battle was between players and NPCs. */
val isPvN = battle.isPvN
/** Whether the battle was between players. */
val isPvP = battle.isPvP
val context = mutableMapOf<String, MoValue>(
"battle" to battle.struct,
"result" to StringValue(result.name.lowercase()),
"has_winner" to DoubleValue(hasWinner),
"was_victory" to DoubleValue(wasVictory),
"was_capture" to DoubleValue(wasCapture),
"was_forfeit" to DoubleValue(wasForfeit),
"was_fled" to DoubleValue(wasFled),
"was_stopped" to DoubleValue(wasStopped),
"is_pvw" to DoubleValue(isPvW),
"is_pvn" to DoubleValue(isPvN),
"is_pvp" to DoubleValue(isPvP),
"winners" to battle.winners.asArrayValue { it.struct },
"losers" to battle.losers.asArrayValue { it.struct },
"players" to battle.actors.filter { it.type == ActorType.PLAYER }.asArrayValue { it.struct },
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct }
).apply {
forfeitedBy?.let { put("forfeited_by", it.struct) }
}
}
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
import com.cobblemon.mod.common.util.asArrayValue
object BattleActorMoLangFunctions : AbstractMoLangFunctionHolder<BattleActor>() {
override fun BattleActor.moLangFunctions(): MutableMap<String, (MoParams) -> Any> {
@@ -25,6 +26,7 @@ object BattleActorMoLangFunctions : AbstractMoLangFunctionHolder<BattleActor>()
functions["is_npc"] = { DoubleValue(actor.type == ActorType.NPC) }
functions["is_player"] = { DoubleValue(actor.type == ActorType.PLAYER) }
functions["is_wild"] = { DoubleValue(actor.type == ActorType.WILD) }
functions["battle_pokemon"] = { actor.pokemonList.asArrayValue { it.struct } }
when (actor) {
is NPCBattleActor -> {
@@ -15,6 +15,8 @@ import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.Minecraft
import net.minecraft.client.ParticleStatus
import net.minecraft.core.particles.BlockParticleOption
import net.minecraft.core.particles.ParticleOptions
import net.minecraft.core.particles.ParticleTypes
@@ -40,13 +42,25 @@ sealed class ParticleData {
val chance: Double,
val amount: Int,
val locatorResolver: (Map<String, MatrixWrapper>) -> List<String>
): ParticleData()
): ParticleData() {
fun amount(): Int = when(Minecraft.getInstance().options.particles().get()) {
ParticleStatus.ALL -> amount
ParticleStatus.DECREASED -> amount / 2
ParticleStatus.MINIMAL -> amount / 4
}
}
data class MinecraftParticle(
val particle: ParticleOptions,
val chance: Double,
val amount: Int
): ParticleData()
): ParticleData() {
fun amount(): Int = when(Minecraft.getInstance().options.particles().get()) {
ParticleStatus.ALL -> amount
ParticleStatus.DECREASED -> amount / 2
ParticleStatus.MINIMAL -> amount / 4
}
}
}
/**
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.AlphaLevelMatchingSensor
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
@@ -76,7 +77,7 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
?: return super.affectWeight(detail, spawnablePosition, weight)
val detailSpecies = pokemonDetail.pokemon.species
?.let { PokemonSpecies.getByName(it) }
?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }
?: return super.affectWeight(detail, spawnablePosition, weight)
val formData = detailSpecies.getForm(pokemonDetail.pokemon.aspects)
@@ -27,6 +27,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.isBoxLoaded
import com.cobblemon.mod.common.util.removeIf
import com.cobblemon.mod.common.util.squeezeWithinBounds
import com.cobblemon.mod.common.util.toBlockPos
import com.cobblemon.mod.common.util.toVec3f
import com.cobblemon.mod.common.util.weightedSelection
import kotlin.math.max
@@ -190,74 +191,61 @@ interface Spawner {
}
fun isValidStartPoint(world: Level, chunk: ChunkAccess, startPos: BlockPos.MutableBlockPos): Boolean {
val y = startPos.y
if (!world.isLoaded(startPos) || !world.isLoaded(startPos.setY(y + 1))) {
val abovePos = startPos.above()
if (!world.isLoaded(startPos) || !world.isLoaded(abovePos)) {
return false
}
val mid = chunk.getBlockState(startPos)
val above = chunk.getBlockState(abovePos)
val mid = chunk.getBlockState(startPos.setY(y))
val above = chunk.getBlockState(startPos.setY(y + 1))
// Above must be non-solid
if (!above.isPathfindable(PathComputationType.AIR)) {
return false
}
// Position must be non-air
if (mid.isAir) {
return false
}
return true
return above.isPathfindable(PathComputationType.AIR) && mid.isAir
}
fun constrainArea(area: SpawningZoneInput): SpawningZoneInput? {
val basePos = BlockPos.MutableBlockPos(area.baseX, area.baseY, area.baseZ)
val originalY = area.baseY
val (chunkX, chunkZ) = Pair(SectionPos.blockToSectionCoord(area.baseX), SectionPos.blockToSectionCoord(area.baseZ))
val world = area.world
val centerPos = area.getCenter().toBlockPos()
val (centerChunkX, centerChunkZ) = Pair(SectionPos.blockToSectionCoord(centerPos.x), SectionPos.blockToSectionCoord(centerPos.z))
// if the chunk isn't loaded, we don't want to go further & we don't want the getChunk function below to load/create the chunk.
if (!area.world.areEntitiesLoaded(ChunkPos.asLong(chunkX, chunkZ))) return null
if (!world.areEntitiesLoaded(ChunkPos.asLong(centerChunkX, centerChunkZ))) return null
val chunk = area.world.getChunk(chunkX, chunkZ, ChunkStatus.FULL) ?: return null
val chunk = world.getChunk(centerChunkX, centerChunkZ, ChunkStatus.FULL) ?: return null
var valid = isValidStartPoint(area.world, chunk, basePos)
val probePos = centerPos.mutable()
var validY = if (isValidStartPoint(world, chunk, probePos)) centerPos.y else null
if (!valid) {
var offset = 1
do {
if (isValidStartPoint(area.world, chunk, basePos.setY(originalY + offset))) {
valid = true
basePos.y = originalY + offset
if (validY == null) {
for (offset in 1..Cobblemon.config.maxVerticalCorrectionBlocks) {
if (isValidStartPoint(world, chunk, probePos.set(centerPos.x, centerPos.y + offset, centerPos.z))) {
validY = centerPos.y + offset
break
} else if (isValidStartPoint(area.world, chunk, basePos.setY(originalY - offset))) {
valid = true
basePos.y = originalY - offset
} else if (isValidStartPoint(world, chunk, probePos.set(centerPos.x, centerPos.y - offset, centerPos.z))) {
validY = centerPos.y - offset
break
}
offset++
} while (offset <= Cobblemon.config.maxVerticalCorrectionBlocks)
}
if (valid) {
val min = area.world.squeezeWithinBounds(basePos)
val max = area.world.squeezeWithinBounds(basePos.move(area.length, area.height, area.width))
if (area.world.isLoaded(min) && area.world.isLoaded(max) &&
min.x < max.x && min.y < max.y && min.z < max.z
) {
return SpawningZoneInput(
cause = area.cause,
world = area.world,
baseX = min.x,
baseY = min.y,
baseZ = min.z,
length = max.x - min.x,
height = max.y - min.y,
width = max.z - min.z
)
}
}
val targetY = validY ?: return null
val newBaseY = (targetY - (area.height / 2)).coerceIn(world.minBuildHeight, world.maxBuildHeight)
val minPos = world.squeezeWithinBounds(BlockPos(area.baseX, newBaseY, area.baseZ))
val maxPos = world.squeezeWithinBounds(BlockPos(area.baseX + area.length, newBaseY + area.height, area.baseZ + area.width))
val finalBox = AABB(
minPos.x.toDouble(), minPos.y.toDouble(), minPos.z.toDouble(),
maxPos.x.toDouble(), maxPos.y.toDouble(), maxPos.z.toDouble()
)
if (minPos.x < maxPos.x && minPos.y < maxPos.y && minPos.z < maxPos.z && world.isBoxLoaded(finalBox)) {
return SpawningZoneInput(
cause = area.cause,
world = world,
baseX = minPos.x,
baseY = minPos.y,
baseZ = minPos.z,
length = maxPos.x - minPos.x,
height = maxPos.y - minPos.y,
width = maxPos.z - minPos.z
)
}
return null
}
@@ -34,6 +34,7 @@ class ElementalType(
val resourceLocation: ResourceLocation = ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "ui/types.png"),
val showdownId: String = ShowdownIdentifiable.REGEX.replace(name.lowercase(), ""),
val typeGem: ResourceLocation = ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, showdownId + "_gem"),
val order: Int = 1000
) : ShowdownIdentifiable {
override fun showdownId(): String {
@@ -25,7 +25,8 @@ object ElementalTypes {
hue = 0xE8E8DA,
textureXMultiplier = 0,
primaryColor = 0x8FA689,
secondaryColor = 0xFFFBE2
secondaryColor = 0xFFFBE2,
order = 0
)
@JvmField
@@ -35,7 +36,8 @@ object ElementalTypes {
hue = 0xFF6E21,
textureXMultiplier = 1,
primaryColor = 0xF92D2D,
secondaryColor = 0xF99B1D
secondaryColor = 0xF99B1D,
order = 1
)
@JvmField
@@ -45,7 +47,8 @@ object ElementalTypes {
hue = 0x3FA5FF,
textureXMultiplier = 2,
primaryColor = 0x377AF6,
secondaryColor = 0x50DDF9
secondaryColor = 0x50DDF9,
order = 2
)
@JvmField
@@ -55,7 +58,8 @@ object ElementalTypes {
hue = 0x62D14F,
textureXMultiplier = 3,
primaryColor = 0x0EAE95,
secondaryColor = 0xC6F554
secondaryColor = 0xC6F554,
order = 3
)
@JvmField
@@ -65,7 +69,8 @@ object ElementalTypes {
hue = 0xFFD314,
textureXMultiplier = 4,
primaryColor = 0xF7AB19,
secondaryColor = 0xFFF257
secondaryColor = 0xFFF257,
order = 4
)
@JvmField
@@ -75,7 +80,8 @@ object ElementalTypes {
hue = 0x54F2F2,
textureXMultiplier = 5,
primaryColor = 0x41BAED,
secondaryColor = 0x91F4F9
secondaryColor = 0x91F4F9,
order = 5
)
@JvmField
@@ -85,7 +91,8 @@ object ElementalTypes {
hue = 0xEF565D,
textureXMultiplier = 6,
primaryColor = 0xC8356B,
secondaryColor = 0xF36A3F
secondaryColor = 0xF36A3F,
order = 6
)
@JvmField
@@ -95,7 +102,8 @@ object ElementalTypes {
hue = 0xD651FF,
textureXMultiplier = 7,
primaryColor = 0x7B41DD,
secondaryColor = 0xE568F4
secondaryColor = 0xE568F4,
order = 7
)
@JvmField
@@ -105,7 +113,8 @@ object ElementalTypes {
hue = 0xF4A453,
textureXMultiplier = 8,
primaryColor = 0xE08835,
secondaryColor = 0xFFD057
secondaryColor = 0xFFD057,
order = 8
)
@JvmField
@@ -115,7 +124,8 @@ object ElementalTypes {
hue = 0xB8B2FF,
textureXMultiplier = 9,
primaryColor = 0x6083F6,
secondaryColor = 0xD5CCFA
secondaryColor = 0xD5CCFA,
order = 9
)
@JvmField
@@ -125,7 +135,8 @@ object ElementalTypes {
hue = 0xFF5E9E,
textureXMultiplier = 10,
primaryColor = 0xE553CE,
secondaryColor = 0xF69DD5
secondaryColor = 0xF69DD5,
order = 10
)
@JvmField
@@ -135,7 +146,8 @@ object ElementalTypes {
hue = 0xD3D319,
textureXMultiplier = 11,
primaryColor = 0x9FBE1B,
secondaryColor = 0xE9FB5B
secondaryColor = 0xE9FB5B,
order = 11
)
@JvmField
@@ -145,7 +157,8 @@ object ElementalTypes {
hue = 0xB7A16E,
textureXMultiplier = 12,
primaryColor = 0x9F814A,
secondaryColor = 0xEECB7A
secondaryColor = 0xEECB7A,
order = 12
)
@JvmField
@@ -155,7 +168,8 @@ object ElementalTypes {
hue = 0x9C80F7,
textureXMultiplier = 13,
primaryColor = 0x4F57DD,
secondaryColor = 0xC182F1
secondaryColor = 0xC182F1,
order = 13
)
@JvmField
@@ -165,7 +179,8 @@ object ElementalTypes {
hue = 0x7580FF,
textureXMultiplier = 14,
primaryColor = 0x4E68E2,
secondaryColor = 0x47C7F7
secondaryColor = 0x47C7F7,
order = 14
)
@JvmField
@@ -175,7 +190,8 @@ object ElementalTypes {
hue = 0x587DA0,
textureXMultiplier = 15,
primaryColor = 0x465B99,
secondaryColor = 0x689EBF
secondaryColor = 0x689EBF,
order = 15
)
@JvmField
@@ -185,7 +201,8 @@ object ElementalTypes {
hue = 0xABD1F4,
textureXMultiplier = 16,
primaryColor = 0x628CB9,
secondaryColor = 0xD6F7F3
secondaryColor = 0xD6F7F3,
order = 16
)
@JvmField
@@ -195,18 +212,21 @@ object ElementalTypes {
hue = 0xFF7FE5,
textureXMultiplier = 17,
primaryColor = 0xE2678C,
secondaryColor = 0xF5A7B7
secondaryColor = 0xF5A7B7,
order = 17
)
@JvmStatic
fun register(name: String, displayName: MutableComponent, hue: Int, textureXMultiplier: Int, primaryColor: Int, secondaryColor: Int): ElementalType {
@JvmOverloads
fun register(name: String, displayName: MutableComponent, hue: Int, textureXMultiplier: Int, primaryColor: Int, secondaryColor: Int, order: Int = 1000): ElementalType {
return ElementalType(
name = name,
displayName = displayName,
hue = hue,
textureXMultiplier = textureXMultiplier,
primaryColor = primaryColor,
secondaryColor = secondaryColor
secondaryColor = secondaryColor,
order = order
).also {
allTypes.add(it)
}
@@ -83,7 +83,8 @@ open class BattlePokemon(
"max_health" to Function { DoubleValue(maxHealth.toDouble()) },
"ivs" to Function { effectedPokemon.ivs.struct },
"nature" to Function { StringValue(effectedPokemon.nature.name.toString()) },
"moveset" to Function { effectedPokemon.moveSet.toStruct() }
"moveset" to Function { effectedPokemon.moveSet.toStruct() },
"has_faced_opponents" to Function { DoubleValue(facedOpponents.isNotEmpty()) }
))
val uuid: UUID
@@ -48,7 +48,8 @@ class DecorativeItemBlock(settings: Properties, val type: DecorativeItemBlockTyp
NEVERMELT,
SCOPE,
WIDE,
ZOOM;
ZOOM,
IZER;
override fun getSerializedName(): String = this.name.lowercase()
@@ -76,6 +77,7 @@ class DecorativeItemBlock(settings: Properties, val type: DecorativeItemBlockTyp
val SCOPE_HITBOX = Shapes.box(0.625, 0.0, 0.4375, 0.9375, 0.125, 0.75)
val WIDE_HITBOX = Shapes.box(0.625, 0.0, 0.125, 0.9375, 0.0625, 0.625)
val ZOOM_HITBOX = Shapes.box(0.125, 0.0, 0.1875, 0.375, 0.1875, 0.5)
val IZER_HITBOX = Shapes.box(0.25, 0.0, 0.25, 0.75, 0.375, 0.75)
fun getShape(type: DecorativeItemBlockType): VoxelShape {
return when (type) {
@@ -87,6 +89,7 @@ class DecorativeItemBlock(settings: Properties, val type: DecorativeItemBlockTyp
DecorativeItemBlockType.SCOPE -> SCOPE_HITBOX
DecorativeItemBlockType.WIDE -> WIDE_HITBOX
DecorativeItemBlockType.ZOOM -> ZOOM_HITBOX
DecorativeItemBlockType.IZER -> IZER_HITBOX
DecorativeItemBlockType.FLATTENED_10x4 -> SMOOSHED4_HITBOX
DecorativeItemBlockType.FLATTENED_8x4 -> FLAT4_HITBOX
DecorativeItemBlockType.FLATTENED_8x6 -> FLAT6_HITBOX
@@ -103,15 +103,15 @@ class MintBlock(private val mintType: MintType, settings: Properties) : CropBloc
GREEN -> CobblemonItems.GREEN_MINT_SEEDS
WHITE -> CobblemonItems.WHITE_MINT_SEEDS
}
fun getLeaf(): MintLeafItem = when (this) {
RED -> CobblemonItems.RED_MINT_LEAF
BLUE -> CobblemonItems.BLUE_MINT_LEAF
CYAN -> CobblemonItems.CYAN_MINT_LEAF
PINK -> CobblemonItems.PINK_MINT_LEAF
GREEN -> CobblemonItems.GREEN_MINT_LEAF
WHITE -> CobblemonItems.WHITE_MINT_LEAF
}
// These don't seem to get called to anywhere besides the direct item, and since I'm trying to do funny stuff there, just commenting this out
// fun getLeaf(): MintLeafItem = when (this) {
// RED -> CobblemonItems.RED_MINT_LEAF
// BLUE -> CobblemonItems.BLUE_MINT_LEAF
// CYAN -> CobblemonItems.CYAN_MINT_LEAF
// PINK -> CobblemonItems.PINK_MINT_LEAF
// GREEN -> CobblemonItems.GREEN_MINT_LEAF
// WHITE -> CobblemonItems.WHITE_MINT_LEAF
// }
fun getCropBlock(): MintBlock = when (this) {
RED -> CobblemonBlocks.RED_MINT
@@ -34,7 +34,9 @@ import net.minecraft.world.item.alchemy.Potions
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.BonemealableBlock
import net.minecraft.world.level.block.DispenserBlock
import net.minecraft.world.level.block.LeavesBlock
import net.minecraft.world.level.block.state.BlockState
@@ -52,7 +54,7 @@ import net.minecraft.world.phys.shapes.EntityCollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings), BonemealableBlock {
companion object {
val AGE: IntegerProperty = BlockStateProperties.AGE_2
val DISTANCE: IntegerProperty = BlockStateProperties.DISTANCE
@@ -181,6 +183,15 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
super.randomTick(state, world, pos, random)
}
override fun isValidBonemealTarget(level: LevelReader, pos: BlockPos, state: BlockState): Boolean =
state.getValue(AGE) < MAX_AGE && !state.getValue(BlockStateProperties.WATERLOGGED)
override fun isBonemealSuccess(level: Level, random: RandomSource, pos: BlockPos, state: BlockState) = true
override fun performBonemeal(level: ServerLevel, random: RandomSource, pos: BlockPos, state: BlockState) {
level.setBlock(pos, changeAge(state, 1), UPDATE_CLIENTS)
}
override fun placeLiquid(level: LevelAccessor, pos: BlockPos, state: BlockState, fluidState: FluidState): Boolean {
if (!state.getValue(BlockStateProperties.WATERLOGGED) && fluidState.type === Fluids.WATER) {
val hasHoney = state.getValue(AGE) > 0
@@ -45,7 +45,9 @@ class StackableItemBlock(settings: Properties, val type: StackableItemBlockType)
IRON_BALL,
THROAT_SPRAY,
UPGRADE,
DICE;
DICE,
GLASS_BOTTLE,
EXTENDER;
override fun getSerializedName(): String = this.name.lowercase()
@@ -133,6 +135,18 @@ class StackableItemBlock(settings: Properties, val type: StackableItemBlockType)
Shapes.box(0.125, 0.0, 0.625, 0.5625, 0.1875, 0.875),
Shapes.box(0.125, 0.0, 0.4375, 0.5625, 0.1875, 0.875),
Shapes.box(0.125, 0.0, 0.4375, 0.5625, 0.375, 0.875)
),
StackableItemBlockType.GLASS_BOTTLE to listOf(
Shapes.box(0.375, 0.0, 0.375, 0.625, 0.375, 0.625),
Shapes.box(0.1875, 0.0, 0.1875, 0.8125, 0.375, 0.6875),
Shapes.box(0.125, 0.0, 0.125, 0.8125, 0.375, 0.875),
Shapes.box(0.125, 0.0, 0.125, 0.875, 0.375, 0.875)
),
StackableItemBlockType.EXTENDER to listOf(
Shapes.box(0.25, 0.0, 0.375, 0.625, 0.5625, 0.625),
Shapes.box(0.125, 0.0, 0.25, 0.875, 0.5625, 0.75),
Shapes.box(0.0625, 0.0, 0.0625, 0.875, 0.5625, 0.875),
Shapes.box(0.0625, 0.0, 0.0625, 0.9375, 0.5625, 0.9375)
)
)
@@ -19,6 +19,7 @@ import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.util.StringRepresentable
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.component.BlockItemStateProperties
@@ -33,8 +34,8 @@ import net.minecraft.world.level.block.Mirror
import net.minecraft.world.level.block.Rotation
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BooleanProperty
import net.minecraft.world.level.block.state.properties.DirectionProperty
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.block.state.properties.IntegerProperty
import net.minecraft.world.level.material.PushReaction
import net.minecraft.world.level.storage.loot.LootParams
@@ -61,22 +62,27 @@ class TypeGemClusterBlock(
}
val gemToClusterMap: MutableMap<Block, TypeGemClusterBlock> = mutableMapOf()
val SHOULD_GROW: BooleanProperty = BooleanProperty.create("should_grow")
val FACING: DirectionProperty = DirectionalBlock.FACING
val STAGE: IntegerProperty = IntegerProperty.create("stage", 0, 3)
val STUNTED: BooleanProperty = BooleanProperty.create("stunted")
val GROWTH_TYPE: EnumProperty<GrowthType> = EnumProperty.create("growth_type", GrowthType::class.java)
fun clusterFromGemBlock(gemBlock: Block): TypeGemClusterBlock? {
return gemToClusterMap[gemBlock]
}
}
enum class GrowthType(private val label: String, val chance: Float): StringRepresentable {
DECORATION("none", 0.25f),
FULL("full", 0.5f),
STUNTED("stunted", 0.25f);
override fun getSerializedName(): String = label
}
init {
registerDefaultState(stateDefinition.any()
.setValue(FACING, Direction.UP)
.setValue(SHOULD_GROW, true)
.setValue(STAGE, 0)
.setValue(STUNTED, false)
.setValue(GROWTH_TYPE, GrowthType.FULL)
)
}
@@ -89,15 +95,19 @@ class TypeGemClusterBlock(
return defaultBlockState()
.setValue(FACING, facing)
.setValue(SHOULD_GROW, shouldGrow)
.setValue(STAGE, 0)
.setValue(STUNTED, false)
.setValue(GROWTH_TYPE, if(shouldGrow) GrowthType.FULL else GrowthType.DECORATION)
}
public override fun isRandomlyTicking(state: BlockState): Boolean = state.getValue(SHOULD_GROW)
public override fun isRandomlyTicking(state: BlockState): Boolean {
// if growth type is either stunted or full, we need to tick
return state.getValue(GROWTH_TYPE) != GrowthType.DECORATION
}
override fun randomTick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
/*
advanceGrowth(state, level, pos, random)
*/
}
fun advanceGrowth(state: BlockState, level: LevelAccessor, pos: BlockPos, random: RandomSource) {
@@ -111,15 +121,8 @@ class TypeGemClusterBlock(
return
}
// At STAGE_3
val isStunted = state.getValue(STUNTED)
val facing = state.getValue(FACING)
if (isStunted) {
level.setBlock(pos, state.setValue(SHOULD_GROW, false), UPDATE_ALL)
return
}
// Check neighboring gem blocks
val hasConflict = Direction.entries
.filter { it != facing.opposite }
@@ -132,61 +135,36 @@ class TypeGemClusterBlock(
if (hasConflict) {
level.setBlock(
pos,
state.setValue(STUNTED, true).setValue(SHOULD_GROW, false),
state.setValue(GROWTH_TYPE, GrowthType.STUNTED),
UPDATE_ALL
)
} else {
}
var nextState = nextStage.defaultBlockState()
if (nextState.hasProperty(FACING)) {
nextState = nextState.setValue(FACING, facing)
}
level.setBlock(pos, nextState, UPDATE_ALL)
attachDecorativeClusters(level, pos, random)
}
if (isGem(nextState)) {
TypeGemCoreBlock.addClustersToBlock(state, pos, level, random)
}
}
private fun isGem(state: BlockState): Boolean {
return state.`is`(CobblemonBlockTags.TYPE_GEM_BLOCKS)
}
private fun attachDecorativeClusters(level: LevelAccessor, gemPos: BlockPos, random: RandomSource) {
val openDirections = Direction.entries.filter { direction ->
level.getBlockState(gemPos.relative(direction)).isAir
}.toMutableList()
if (openDirections.isEmpty()) {
return
}
val minClusters = maxOf(1, (openDirections.size * 0.75f).toInt())
val clusterCount = random.nextInt(minClusters, openDirections.size + 1)
repeat(clusterCount) {
if (openDirections.isEmpty()) return@repeat
val index = random.nextInt(openDirections.size)
val direction = openDirections.removeAt(index)
val clusterPos = gemPos.relative(direction)
val stage = random.nextInt(0, 4)
val clusterState = defaultBlockState()
.setValue(FACING, direction)
.setValue(STAGE, stage)
.setValue(SHOULD_GROW, false) // so we can reduce lag... hopefully
.setValue(STUNTED, false)
level.setBlock(clusterPos, clusterState, UPDATE_ALL)
}
}
fun gemClusterCanGrow(state: BlockState, level: LevelReader, pos: BlockPos): Boolean {
if (!state.getValue(SHOULD_GROW)) return false
if (state.getValue(GROWTH_TYPE) == GrowthType.DECORATION) return false
if (state.getValue(GROWTH_TYPE) == GrowthType.STUNTED
&& state.getValue(STAGE) == 3) return false
val supportPos = pos.relative(state.getValue(FACING).opposite)
val supportBlock = level.getBlockState(supportPos).block
return CobblemonBlocks.typeGemBlocks().containsValue(supportBlock) || (supportBlock == CobblemonBlocks.TYPE_GEM_CORE) // Cannot grow if not on any gem blocks
}
override fun getDrops(state: BlockState, params: LootParams.Builder): List<ItemStack> {
val drops = super.getDrops(state, params)
@@ -200,8 +178,7 @@ class TypeGemClusterBlock(
DataComponents.BLOCK_STATE,
BlockItemStateProperties.EMPTY
.with(STAGE, state.getValue(STAGE))
.with(SHOULD_GROW, false)
.with(STUNTED, false)
.with(GROWTH_TYPE, GrowthType.DECORATION)
)
stack.set(
DataComponents.CUSTOM_MODEL_DATA,
@@ -272,7 +249,7 @@ class TypeGemClusterBlock(
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
super.createBlockStateDefinition(builder)
builder.add(FACING, SHOULD_GROW, STAGE, STUNTED)
builder.add(FACING, STAGE, GROWTH_TYPE)
}
override fun getCloneItemStack(level: LevelReader, pos: BlockPos, state: BlockState): ItemStack {
@@ -283,8 +260,7 @@ class TypeGemClusterBlock(
DataComponents.BLOCK_STATE,
BlockItemStateProperties.EMPTY
.with(STAGE, state.getValue(STAGE))
.with(SHOULD_GROW, false)
.with(STUNTED, false)
.with(GROWTH_TYPE, GrowthType.DECORATION)
)
stack.set(
DataComponents.CUSTOM_MODEL_DATA,
@@ -11,8 +11,10 @@ package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags
import com.cobblemon.mod.common.block.TypeGemClusterBlock.Companion.SHOULD_GROW
import com.cobblemon.mod.common.block.TypeGemClusterBlock.Companion.STUNTED
import com.cobblemon.mod.common.block.TypeGemClusterBlock.Companion.FACING
import com.cobblemon.mod.common.block.TypeGemClusterBlock.Companion.GROWTH_TYPE
import com.cobblemon.mod.common.block.TypeGemClusterBlock.Companion.STAGE
import com.cobblemon.mod.common.block.TypeGemClusterBlock.GrowthType
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.registries.BuiltInRegistries
@@ -21,8 +23,8 @@ import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.WorldGenLevel
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.DirectionalBlock
import net.minecraft.world.level.block.state.BlockState
import java.util.*
@@ -30,13 +32,6 @@ import java.util.*
class TypeGemCoreBlock(properties: Properties) : Block(properties) {
companion object {
const val MAX_CONNECTED_GEMS = 7
const val MIN_DISTANCE_BETWEEN_GEMS = 1
const val CONTINUATION_CHANCE = 0.8f
// Upper safety check to prevent infinite loops
const val MAX_FORCE_GROW_ATTEMPTS = 64
val BLOCK_TO_CLUSTER: Map<ResourceLocation, Block> by lazy {
mapOf(
ResourceLocation.parse("cobblemon:normal_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_NORMAL,
@@ -60,28 +55,6 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
)
}
fun setStuntState(level: LevelAccessor, gemBlocks: List<Pair<BlockState, BlockPos>>, stunted: Boolean) {
for ((_, gemPos) in gemBlocks) {
for (dir in Direction.entries) {
val neighborPos = gemPos.relative(dir)
val neighborState = level.getBlockState(neighborPos)
if (neighborState.block is TypeGemClusterBlock) {
if (neighborState.hasProperty(STUNTED) && neighborState.getValue(STUNTED) != stunted) {
var updatedState = neighborState.setValue(STUNTED, stunted)
if (updatedState.hasProperty(SHOULD_GROW)) {
updatedState = updatedState.setValue(SHOULD_GROW, !stunted)
}
level.setBlock(neighborPos, updatedState, 3)
}
}
}
}
}
fun getConnectedGemBlocks(level: BlockGetter, pos: BlockPos): List<Pair<BlockState, BlockPos>> {
val connectedGems = mutableListOf<Pair<BlockState, BlockPos>>()
val visited = mutableSetOf<BlockPos>()
@@ -107,119 +80,159 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
}
return connectedGems
}
fun addClustersToBlock(state: BlockState, pos: BlockPos, level: LevelAccessor, random: RandomSource) {
Direction.entries.forEach {
if (random.nextFloat() < Cobblemon.config.typeGemGrowthChance) {
val faceState = level.getBlockState(pos.relative(it))
val randomGrowthType = decideClusterGrowthType(level, pos)
val newState = BLOCK_TO_CLUSTER[BuiltInRegistries.BLOCK.getKey(state.block)]?.defaultBlockState()
?.setValue(DirectionalBlock.FACING, it)
?.setValue(GROWTH_TYPE, randomGrowthType)
?: return
if (faceState.`is`(Blocks.AIR)) {
level.setBlock(pos.relative(it), newState, 3)
}
}
}
}
private fun decideClusterGrowthType(level: LevelAccessor, pos: BlockPos, random: RandomSource = RandomSource.create()): GrowthType {
val growthTypes = if (getConnectedGemBlocks(level, pos).size > Cobblemon.config.typeGemMaxConnected) {
listOf(GrowthType.DECORATION, GrowthType.STUNTED)
} else {
GrowthType.entries
}
val totalChance = growthTypes.sumOf { it.chance.toDouble() }
var roll = random.nextDouble() * totalChance
for (type in growthTypes) {
roll -= type.chance.toDouble()
if (roll <= 0.0) {
return type
}
}
return GrowthType.DECORATION
}
}
private fun getConnectedClusters(level: LevelAccessor, pos: BlockPos): List<Pair<BlockState, BlockPos>> {
val gemBlocks = getConnectedGemBlocks(level, pos)
val clusters = mutableListOf<Pair<BlockState, BlockPos>>()
val visited = mutableSetOf<BlockPos>()
for ((gemState, gemPos) in gemBlocks) {
val expectedCluster = BLOCK_TO_CLUSTER[BuiltInRegistries.BLOCK.getKey(gemState.block)] ?: continue
for (direction in Direction.entries) {
val clusterPos = gemPos.relative(direction)
if (!visited.add(clusterPos)) continue
val clusterState = level.getBlockState(clusterPos)
if (clusterState.block == expectedCluster) {
clusters += clusterState to clusterPos
}
}
}
return clusters
}
override fun randomTick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
grow(level, pos, random)
}
// should we tick at all?
if (random.nextFloat() >= Cobblemon.config.typeGemTickChance) {
return
}
val gemCount = getConnectedGemBlocks(level, pos).size
fun forceGrow(level: WorldGenLevel, pos: BlockPos, random: RandomSource, percentage: Float) {
val desiredLength = MAX_CONNECTED_GEMS * percentage
repeat(MAX_FORCE_GROW_ATTEMPTS) {
val (grown, clusterSize) = grow(level, pos, random, true)
if (!grown || clusterSize >= desiredLength) return
// if growth has stopped fully but min growth hasn't been reached, randomly set a stopped bud to GROWTH_TYPE full
val clusters = getConnectedClusters(level, pos)
val fullClusterCount = clusters.count { (clusterState, _) ->
clusterState.getValue(GROWTH_TYPE) == GrowthType.FULL
}
Cobblemon.LOGGER.warn(
"Forced type gem growth at {} stopped after {} attempts without reaching its target size; keeping the partial formation.",
pos,
MAX_FORCE_GROW_ATTEMPTS
)
}
private fun grow(
level: WorldGenLevel,
pos: BlockPos,
random: RandomSource,
forced: Boolean = false
): Pair<Boolean, Int> {
val connectedGems = getConnectedGemBlocks(level, pos) // maybe we can store this and access it for better performance? check for changes in list rather than checking each time grow is called? idk
val gemCount = connectedGems.size
val overLimit = gemCount >= MAX_CONNECTED_GEMS
if (overLimit) {
// if there is no open air pockets to grow any new clusters then exit early
if (!hasBreathingRoom(level, connectedGems)) {
return Pair(false, gemCount)
}
// max type gem block count met, tell clusters to grow but not turn into blocks
setStuntState(level, connectedGems, true)
//return Pair(false, gemCount)
} else {
// make sure connected clusters know they can grow and turn into blocks
setStuntState(level, connectedGems, false)
}
val javaRandom = java.util.Random(random.nextLong())
for ((gemState, gemPos) in connectedGems.shuffled(javaRandom)) {
val registryKey = BuiltInRegistries.BLOCK.getKey(gemState.block)
val clusterBlock = BLOCK_TO_CLUSTER[registryKey] ?: continue // If there is no block to grow, skip the block
for (dir in Direction.entries.shuffled(javaRandom)) {
val targetPos = gemPos.relative(dir)
val targetState = level.getBlockState(targetPos)
if (!targetState.isAir) continue
if (!isPositionValidForGrowth(level, targetPos)) continue
// Place gem cluster
val placeState = clusterBlock.defaultBlockState()
.setValue(DirectionalBlock.FACING, dir)
.setValue(TypeGemClusterBlock.STAGE, 0)
.setValue(SHOULD_GROW, true)
level.setBlock(targetPos, placeState, UPDATE_ALL)
// During world gen, the region silently discards writes into neighboring chunks that are already fully generated.
// Through ImposterProtoChunk with writes set to disabled. Checks if the block is still air after the write and skips if so as it can't be filled.
// Preventing infinite loops.
if (!level.getBlockState(targetPos).`is`(clusterBlock)) continue
if (forced) {
forceAdvanceClusterGrowth(level, targetPos, random)
}
val updatedGemCount = if (forced) getConnectedGemBlocks(level, pos).size else connectedGems.size
return Pair(true, updatedGemCount)
if (fullClusterCount == 0) {
if (gemCount < Cobblemon.config.typeGemMinGrowth && clusters.isNotEmpty()) {
println("Force set a cluster to FULL at size $gemCount")
val randomCluster = clusters.random()
level.setBlockAndUpdate(randomCluster.second, randomCluster.first.setValue(GROWTH_TYPE, GrowthType.FULL))
}
}
// println("[TypeGemCoreBlock] No valid spot found for gem placement.")
return Pair(false, connectedGems.size)
expand(level, pos, random)
}
private fun forceAdvanceClusterGrowth(level: WorldGenLevel, clusterPos: BlockPos, random: RandomSource) {
repeat(5) {
val clusterState = level.getBlockState(clusterPos)
val clusterBlock = clusterState.block as? TypeGemClusterBlock ?: return
clusterBlock.advanceGrowth(clusterState, level, clusterPos, random)
fun expand(level: LevelAccessor, pos: BlockPos, random: RandomSource, forceGrow: Boolean = false) {
getConnectedGemBlocks(level, pos).forEach {
val state = it.first
val pos = it.second
addClustersToBlock(state, pos, level, random)
growClusters(pos, level, random, forceGrow)
}
}
private fun hasBreathingRoom(level: WorldGenLevel, gems: List<Pair<BlockState, BlockPos>>): Boolean {
for ((_, gemPos) in gems) {
for (dir in Direction.entries) {
if (level.getBlockState(gemPos.relative(dir)).isAir) {
return true
}
private fun growClusters(pos: BlockPos, level: LevelAccessor, random: RandomSource, forceGrow: Boolean) {
Direction.entries.forEach { direction ->
val relativePos = pos.relative(direction)
val relativeState = level.getBlockState(relativePos)
val clusterBlock = relativeState.block as? TypeGemClusterBlock ?: return@forEach
if ((relativeState.getValue(DirectionalBlock.FACING) == direction &&
random.nextFloat() < Cobblemon.config.typeGemGrowthChance) || forceGrow
) {
clusterBlock.advanceGrowth(relativeState, level, relativePos, random)
}
}
return false
}
private fun isPositionValidForGrowth(level: WorldGenLevel, pos: BlockPos): Boolean {
return Direction.entries.none { dir ->
val nearby = pos.relative(dir)
isGem(level.getBlockState(nearby)) &&
pos.distManhattan(nearby) < MIN_DISTANCE_BETWEEN_GEMS
private fun addInitialClusters(pos: BlockPos, level: ServerLevel, clusterType: TypeGemClusterBlock) {
Direction.entries.forEach {
val faceState = level.getBlockState(pos.relative(it))
if (faceState.`is`(Blocks.AIR)) {
level.setBlockAndUpdate(pos.relative(it), clusterType.defaultBlockState().setValue(
DirectionalBlock.FACING, it)
.setValue(GROWTH_TYPE, GrowthType.FULL)
)
}
}
}
private fun isGem(state: BlockState): Boolean {
return state.`is`(CobblemonBlockTags.TYPE_GEM_BLOCKS)
}
override fun isRandomlyTicking(state: BlockState): Boolean = true
}
private fun attachDecorativeClusters(level: LevelAccessor, gemPos: BlockPos, random: RandomSource) {
val openDirections = Direction.entries.filter { direction ->
level.getBlockState(gemPos.relative(direction)).isAir
}.toMutableList()
if (openDirections.isEmpty()) {
return
}
val gemState = level.getBlockState(gemPos)
val clusterBlock = BLOCK_TO_CLUSTER[BuiltInRegistries.BLOCK.getKey(gemState.block)] ?: return
val minClusters = maxOf(1, (openDirections.size * 0.75f).toInt())
val clusterCount = random.nextInt(minClusters, openDirections.size + 1)
repeat(clusterCount) {
if (openDirections.isEmpty()) return@repeat
val index = random.nextInt(openDirections.size)
val direction = openDirections.removeAt(index)
val clusterPos = gemPos.relative(direction)
val stage = random.nextInt(0, 4)
val clusterState = clusterBlock.defaultBlockState()
.setValue(FACING, direction)
.setValue(STAGE, stage)
.setValue(GROWTH_TYPE, GrowthType.DECORATION)
level.setBlock(clusterPos, clusterState, UPDATE_ALL)
}
}
}
@@ -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.block.decor
import net.minecraft.core.BlockPos
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.SimpleWaterloggedBlock
import net.minecraft.world.level.block.TallFlowerBlock
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
import net.minecraft.world.level.material.FluidState
import net.minecraft.world.level.material.Fluids
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
class LobailaFlowerBlock(properties: Properties?) : TallFlowerBlock(properties), SimpleWaterloggedBlock {
init {
registerDefaultState(stateDefinition.any()
.setValue(HALF, DoubleBlockHalf.LOWER)
.setValue(WATERLOGGED, false))
}
override fun getFluidState(blockState: BlockState): FluidState? {
return if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState);
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(HALF, WATERLOGGED)
}
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
val fluidState = context.level.getFluidState(context.clickedPos)
return this.defaultBlockState()
.setValue(
WATERLOGGED,
fluidState.type === Fluids.WATER
)
}
override fun getShape(state: BlockState, world: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape = AABB
companion object {
private val AABB = Shapes.box(0.125, 0.0, 0.125, 0.875, 1.0, 0.875)
}
}
@@ -0,0 +1,87 @@
/*
* 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.decor
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.block.entity.MistleafFlowerBlockEntity
import net.minecraft.core.BlockPos
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.BaseEntityBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.SoundType
import net.minecraft.world.level.block.TallFlowerBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
import net.minecraft.world.level.block.state.properties.IntegerProperty
import net.minecraft.world.level.material.MapColor
import net.minecraft.world.level.material.PushReaction
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
class MistleafFlowerBlock(lightLevel: (BlockState) -> Int) :
EntityBlock,
TallFlowerBlock(
Properties.of()
.mapColor(MapColor.PLANT)
.noCollission()
.instabreak()
.sound(SoundType.GRASS)
.offsetType(OffsetType.XZ)
.ignitedByLava()
.pushReaction(PushReaction.DESTROY)
.lightLevel(lightLevel)
) {
init {
registerDefaultState(stateDefinition.any()
.setValue(HALF, DoubleBlockHalf.LOWER)
.setValue(GLOWING, 0))
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(HALF, GLOWING)
}
override fun isValidBonemealTarget(level: LevelReader, pos: BlockPos, state: BlockState): Boolean {
return false
}
override fun getShape(state: BlockState, world: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape = AABB
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
return MistleafFlowerBlockEntity(pos, state)
}
override fun <T : BlockEntity?> getTicker(
level: Level,
state: BlockState,
blockEntityType: BlockEntityType<T?>
): BlockEntityTicker<T?>? {
return if (level.isClientSide) null else BaseEntityBlock.createTickerHelper(blockEntityType as BlockEntityType<*>,
CobblemonBlockEntities.MISTLEAF_FLOWER, MistleafFlowerBlockEntity::serverTick) as BlockEntityTicker<T?>?
}
companion object {
private val AABB = Shapes.box(0.125, 0.0, 0.125, 0.875, 1.0, 0.875)
val GLOWING = IntegerProperty.create("glowing", 0, 8)
}
override fun hasAnalogOutputSignal(state: BlockState): Boolean { return true }
override fun getAnalogOutputSignal(state: BlockState, level: Level, pos: BlockPos): Int {
return state.getValue(GLOWING) as Int
}
}
@@ -0,0 +1,104 @@
/*
* 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.decor
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.BonemealableBlock
import net.minecraft.world.level.block.DirectionalBlock
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
class PauvilleaFlowerBlock(properties: Properties?) : DirectionalBlock(properties), BonemealableBlock {
init {
registerDefaultState(stateDefinition.any()
.setValue(FACING, Direction.DOWN))
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(FACING)
}
override fun getStateForPlacement(ctx: BlockPlaceContext): BlockState? {
var blockState = defaultBlockState()
val worldView = ctx.level
val blockPos = ctx.clickedPos
blockState = blockState.setValue(FACING, ctx.clickedFace) as BlockState
if (blockState.canSurvive(worldView, blockPos)) {
return blockState
}
return null
}
override fun updateShape(state: BlockState, direction: Direction, neighborState: BlockState, level: LevelAccessor, pos: BlockPos, neighborPos: BlockPos): BlockState {
val facing = state.getValue(FACING)
if (direction == facing.opposite && !canSurvive(state, level, pos)) {
return Blocks.AIR.defaultBlockState()
}
return super.updateShape(state, direction, neighborState, level, pos, neighborPos)
}
override fun canSurvive(state: BlockState, level: LevelReader, pos: BlockPos): Boolean {
val direction = state.getValue(FACING) as Direction
val blockState = level.getBlockState(pos.relative(direction.opposite))
return blockState.isCollisionShapeFullBlock(level, pos) or blockState.canOcclude()
}
override fun codec(): MapCodec<PauvilleaFlowerBlock> = CODEC
override fun getShape(state: BlockState, blockGetter: BlockGetter, pos: BlockPos, collisionContext: CollisionContext): VoxelShape {
return when (state.getValue(FACING)) {
Direction.DOWN -> CEILING
Direction.NORTH -> WALL_NORTH
Direction.EAST -> WALL_EAST
Direction.SOUTH -> WALL_SOUTH
Direction.WEST -> WALL_WEST
Direction.UP -> FLOOR
}
}
companion object {
val CODEC: MapCodec<PauvilleaFlowerBlock> = RecordCodecBuilder.mapCodec {
it.group(propertiesCodec()).apply(it, ::PauvilleaFlowerBlock)
}
val FLOOR = Shapes.box(0.075, 0.0, 0.075, 0.925, 0.4375, 0.925)
val WALL_NORTH = Shapes.box(0.0, 0.0, 0.8125, 1.0, 1.0, 1.0)
val WALL_EAST = Shapes.box(0.0, 0.0, 0.0, 0.1875, 1.0, 1.0)
val WALL_SOUTH = Shapes.box(0.0, 0.0, 0.0, 1.0, 1.0, 0.1875)
val WALL_WEST = Shapes.box(0.8125, 0.0, 0.0, 1.0, 1.0, 1.0)
val CEILING = Shapes.box(0.075, 0.0, 0.075, 0.925, 1.0, 0.925)
}
override fun isValidBonemealTarget(level: LevelReader?, pos: BlockPos?, state: BlockState?): Boolean {
return true
}
override fun isBonemealSuccess(level: Level?, random: RandomSource?, pos: BlockPos?, state: BlockState?): Boolean {
return true
}
override fun performBonemeal(level: ServerLevel, random: RandomSource?, pos: BlockPos, state: BlockState?) {
popResource(level, pos, ItemStack(this))
}
}
@@ -0,0 +1,29 @@
/*
* 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.decor
import net.minecraft.core.BlockPos
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.block.PinkPetalsBlock
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
class PomohanaFlowerBlock(properties: Properties?) : PinkPetalsBlock(properties) {
override fun getShape(state: BlockState, world: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape = AABB
companion object {
private val AABB = Shapes.box(0.125, 0.0, 0.125, 0.875, 1.0, 0.875)
}
}
@@ -0,0 +1,105 @@
/*
* 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.decor
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.entity.TerrainPlantBlockEntity
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.Entity
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.BaseEntityBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.TallFlowerBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BooleanProperty
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
class TerrainPlantBlock(properties: Properties) : TallFlowerBlock(properties), EntityBlock {
init {
registerDefaultState(stateDefinition.any()
.setValue(HALF, DoubleBlockHalf.LOWER)
.setValue(GLOWING, false))
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(HALF, GLOWING)
}
override fun isValidBonemealTarget(level: LevelReader, pos: BlockPos, state: BlockState): Boolean {
return false
}
override fun tick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
if (state.`is`(CobblemonBlocks.LUCIBELL)) { this.checkInside(level, pos, state) }
}
private fun checkInside(level: Level, pos: BlockPos, state: BlockState) {
// Only lower will handle this
val upperState = level.getBlockState(pos.above()).takeIf { it.`is`(CobblemonBlocks.LUCIBELL) && it.getValue(HALF) == DoubleBlockHalf.UPPER }
val entityInside = level.getEntities(null, state.getShape(level, pos).bounds().move(pos)).isNotEmpty()
|| upperState?.let { level.getEntities(null, it.getShape(level, pos.above()).bounds().move(pos.above())).isNotEmpty() } ?: false
val glowingState = state.getValue(GLOWING)
if (glowingState != entityInside) {
level.setBlock(pos, state.setValue(GLOWING, entityInside), UPDATE_CLIENTS)
upperState?.let { level.setBlock(pos.above(), it.setValue(GLOWING, entityInside), UPDATE_CLIENTS) }
}
if (entityInside) level.scheduleTick(pos, this, 30) // tick occasionally to check if player inside
}
override fun entityInside(state: BlockState, level: Level, pos: BlockPos, entity: Entity) {
// Lucibell lower block will be our 'driver'
if (!level.isClientSide && !state.getValue(GLOWING) && state.`is`(CobblemonBlocks.LUCIBELL)) {
val halfState = state.getValue(HALF)
if (halfState == DoubleBlockHalf.UPPER) {
val lowerState = level.getBlockState(pos.below())
.takeIf { it.`is`(CobblemonBlocks.LUCIBELL) && it.getValue(HALF) == DoubleBlockHalf.LOWER }
?: return
(lowerState.block as TerrainPlantBlock).checkInside(level, pos.below(), lowerState)
} else {
checkInside(level, pos, state)
}
}
}
override fun getShape(state: BlockState, world: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape = AABB
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
return TerrainPlantBlockEntity(pos, state)
}
override fun <T : BlockEntity> getTicker(
level: Level,
state: BlockState,
blockEntityType: BlockEntityType<T?>
): BlockEntityTicker<T?>? {
return if (level.isClientSide) null else BaseEntityBlock.createTickerHelper(blockEntityType as BlockEntityType<*>,
CobblemonBlockEntities.TERRAIN_PLANT, TerrainPlantBlockEntity::serverTick) as BlockEntityTicker<T?>?
}
companion object {
private val AABB = Shapes.box(0.125, 0.0, 0.125, 0.875, 1.0, 0.875)
val GLOWING = BooleanProperty.create("glowing")
}
}
@@ -0,0 +1,273 @@
/*
* 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.decor
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.util.StringRepresentable
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.*
import net.minecraft.world.level.block.*
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.block.state.properties.IntegerProperty
import net.minecraft.world.level.material.Fluids
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
@Suppress("OVERRIDE_DEPRECATION")
class TerrainSeedBlock(private val terrainSeedType: TerrainSeedType, settings: Properties) : CropBlock(settings) {
companion object {
val CODEC: MapCodec<TerrainSeedBlock> = RecordCodecBuilder.mapCodec { it.group(
TerrainSeedType.CODEC.fieldOf("terrainSeedType").forGetter(TerrainSeedBlock::terrainSeedType),
propertiesCodec()
).apply(it, ::TerrainSeedBlock) }
const val MATURE_AGE = 4
val AGE: IntegerProperty = IntegerProperty.create("age", 0, MATURE_AGE)
val HALF: EnumProperty<DoubleBlockHalf> = BlockStateProperties.DOUBLE_BLOCK_HALF
val AGE_TO_SHAPE = arrayOf(
box(2.0, 0.0, 2.0, 14.0, 6.0, 14.0), // Stage 0
box(2.0, 0.0, 2.0, 14.0, 16.0, 14.0), // Stage 1
box(2.0, 0.0, 2.0, 14.0, 16.0, 14.0), // Stage 2
box(2.0, 0.0, 2.0, 14.0, 16.0, 14.0), // Stage 3
box(2.0, 0.0, 2.0, 14.0, 16.0, 14.0), // Stage 4
)
val AGE_TO_SHAPE_TOP = arrayOf(
box(2.0, 0.0, 2.0, 14.0, 1.0, 14.0), // Stage 0
box(2.0, 0.0, 2.0, 14.0, 1.0, 14.0), // Stage 1
box(2.0, 0.0, 2.0, 14.0, 8.0, 14.0), // Stage 2
box(2.0, 0.0, 2.0, 14.0, 16.0, 14.0), // Stage 3
box(2.0, 0.0, 2.0, 14.0, 16.0, 14.0), // Stage 4
)
}
override fun codec(): MapCodec<out CropBlock> {
return CODEC
}
init {
this.registerDefaultState(
this.stateDefinition.any()
.setValue(AGE, 0)
.setValue(HALF, DoubleBlockHalf.LOWER)
)
}
override fun getAgeProperty(): IntegerProperty = AGE
override fun getMaxAge(): Int = MATURE_AGE
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(AGE, HALF)
}
override fun getBaseSeedId(): ItemLike = this.terrainSeedType.getSeed()
override fun getShape(state: BlockState, world: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape =
if (state.getValue(HALF) == DoubleBlockHalf.UPPER) AGE_TO_SHAPE_TOP[getAge(state)] else AGE_TO_SHAPE[this.getAge(state)]
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
if (state.getValue(HALF) == DoubleBlockHalf.UPPER || !canGrow(world, pos, state)) return
if (hasSufficientLight(world, pos) && random.nextInt(32) == 0) {
grow(world, pos, state, 1)
}
}
private fun canGrow(world: LevelReader, pos: BlockPos, state: BlockState): Boolean {
return !this.isMaxAge(state) && canSurvive(state, world, pos) && !(!canGrowInto(world, pos.above()) && state.getValue(AGE) >= 4)
}
private fun canGrowInto(world: LevelReader, pos: BlockPos): Boolean {
val blockState = world.getBlockState(pos)
return blockState.isAir || blockState.`is`(this.terrainSeedType.getCropBlock())
}
override fun updateShape(state: BlockState, direction: Direction, neighborState: BlockState, world: LevelAccessor, pos: BlockPos, neighborPos: BlockPos): BlockState {
return if (state.getValue(AGE) >= 2) {
super.updateShape(state, direction, neighborState, world, pos, neighborPos)
} else {
if (state.canSurvive(world, pos)) state else Blocks.AIR.defaultBlockState()
}
}
override fun isValidBonemealTarget(level: LevelReader, pos: BlockPos, state: BlockState): Boolean {
val posAndState = getLowerHalf(level, pos, state)
return if (posAndState == null) false else this.canGrow(
level,
posAndState.first,
posAndState.second
)
}
override fun performBonemeal(level: ServerLevel, random: RandomSource, pos: BlockPos, state: BlockState) {
val posAndState = getLowerHalf(level, pos, state)
if (posAndState != null) {
grow(level, posAndState.first, posAndState.second, getBonemealAgeIncrease(level))
}
}
fun grow(world: Level, pos: BlockPos, state: BlockState, increment: Int) {
if (!canGrow(world, pos, state)) return
val newAge = (this.getAge(state) + increment).coerceAtMost(this.maxAge)
world.setBlock(pos, state.setValue(this.ageProperty, newAge), UPDATE_CLIENTS)
val abovePos = pos.above()
val stateAbove = world.getBlockState(abovePos)
// Set top half depending on age
if (newAge >= (2)) {
if (stateAbove.isAir) {
world.setBlock(
abovePos,
this.defaultBlockState().setValue(AGE, newAge).setValue(HALF, DoubleBlockHalf.UPPER),
UPDATE_CLIENTS
)
}
else if (stateAbove.hasProperty(HALF) && stateAbove.getValue(HALF) == DoubleBlockHalf.UPPER) {
world.setBlock(
abovePos,
stateAbove.setValue(AGE, newAge),
UPDATE_CLIENTS
)
}
}
// Swaps blocks to the actual Flower when fully grown
if (newAge == this.maxAge) {
val nextStateLower = this.terrainSeedType.getFlowerBlock().defaultBlockState().setValue(HALF, DoubleBlockHalf.LOWER)
val nextStateUpper = this.terrainSeedType.getFlowerBlock().defaultBlockState().setValue(HALF, DoubleBlockHalf.UPPER)
world.setBlock(abovePos, nextStateUpper, UPDATE_CLIENTS)
world.setBlock(pos, nextStateLower, UPDATE_CLIENTS)
}
}
override fun getBonemealAgeIncrease(level: Level): Int {
return 1
}
override fun canSurvive(state: BlockState, world: LevelReader, pos: BlockPos): Boolean {
return when (state.getValue(HALF)) {
DoubleBlockHalf.LOWER -> {
val floorBlock = pos.below()
val floor = world.getBlockState(floorBlock)
floor.`is`(Blocks.FARMLAND)
}
DoubleBlockHalf.UPPER -> {
getLowerHalf(world, pos, state) != null
// Upper part survives only if the lower part is valid
}
}
}
private fun getLowerHalf(level: LevelReader, pos: BlockPos, state: BlockState): Pair<BlockPos, BlockState>? {
if (isLower(state)) {
return Pair(pos, state)
} else {
val blockPos = pos.below()
val blockState = level.getBlockState(blockPos)
return if (isLower(blockState)) Pair(
blockPos,
blockState
) else null
}
}
private fun isLower(state: BlockState): Boolean =
state.`is`(this.terrainSeedType.getCropBlock()) && state.getValue(HALF) == DoubleBlockHalf.LOWER
override fun getSoundType(state: BlockState): SoundType {
return CobblemonSounds.HEARTY_GRAINS_SOUNDS
}
@Suppress("unused")
enum class TerrainSeedType : StringRepresentable {
ELECTRIC,
PSYCHIC,
MISTY,
GRASSY;
fun getSeed(): Item = when (this) {
ELECTRIC -> CobblemonItems.ELECTRIC_SEED
PSYCHIC -> CobblemonItems.PSYCHIC_SEED
MISTY -> CobblemonItems.MISTY_SEED
GRASSY -> CobblemonItems.GRASSY_SEED
}
fun getCropBlock(): TerrainSeedBlock = when (this) {
ELECTRIC -> CobblemonBlocks.ELECTRIC_SEED
PSYCHIC -> CobblemonBlocks.PSYCHIC_SEED
MISTY -> CobblemonBlocks.MISTY_SEED
GRASSY -> CobblemonBlocks.GRASSY_SEED
}
fun getFlowerBlock(): Block = when (this) {
ELECTRIC -> CobblemonBlocks.VOLTACONIA
PSYCHIC -> CobblemonBlocks.LUCIBELL
MISTY -> CobblemonBlocks.MISTLEAF
GRASSY -> CobblemonBlocks.VERDROOT
}
override fun getSerializedName(): String = this.name.lowercase()
companion object {
val CODEC = StringRepresentable.fromEnum(::values)
}
}
override fun playerWillDestroy(level: Level, pos: BlockPos, state: BlockState, player: Player): BlockState {
if (!level.isClientSide) {
if (player.isCreative()) {
preventDropFromBottomPart(level, pos, state, player)
} else {
dropResources(state, level, pos, null as BlockEntity?, player, player.getMainHandItem())
}
}
return super.playerWillDestroy(level, pos, state, player)
}
override fun playerDestroy(
level: Level,
player: Player,
pos: BlockPos,
state: BlockState,
blockEntity: BlockEntity?,
tool: ItemStack
) {
super.playerDestroy(level, player, pos, Blocks.AIR.defaultBlockState(), blockEntity, tool)
}
fun preventDropFromBottomPart(level: Level, pos: BlockPos, state: BlockState, player: Player?) {
val doubleblockhalf = state.getValue<DoubleBlockHalf?>(DoublePlantBlock.HALF) as DoubleBlockHalf
if (doubleblockhalf == DoubleBlockHalf.UPPER) {
val blockpos = pos.below()
val blockstate = level.getBlockState(blockpos)
if (blockstate.`is`(state.getBlock()) && blockstate.getValue<DoubleBlockHalf?>(DoublePlantBlock.HALF) == DoubleBlockHalf.LOWER) {
val blockstate1 = if (blockstate.getFluidState()
.`is`(Fluids.WATER)
) Blocks.WATER.defaultBlockState() else Blocks.AIR.defaultBlockState()
level.setBlock(blockpos, blockstate1, 35)
level.levelEvent(player, 2001, blockpos, getId(blockstate))
}
}
}
}
@@ -0,0 +1,80 @@
/*
* 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.decor
import com.cobblemon.mod.common.CobblemonBlocks
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.level.block.state.properties.BooleanProperty
interface WistensuFlowerBlock {
fun additionalBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(BlockStateProperties.FACING)
builder.add(ROOT)
}
fun adjustStateForPlacement(context: BlockPlaceContext, defaultState: BlockState): BlockState {
val upperBlock = context.level.getBlockState(context.clickedPos.relative(Direction.UP))
if (upperBlock.`is`(CobblemonBlocks.WISTENSU) || upperBlock.`is`(CobblemonBlocks.WISTENSU_VINE)) {
return defaultState
.setValue(BlockStateProperties.FACING, Direction.DOWN)
.setValue(ROOT, false)
} else {
var placeDirection = context.clickedFace
if (placeDirection == Direction.UP) placeDirection = Direction.DOWN
return defaultState
.setValue(BlockStateProperties.FACING, placeDirection)
.setValue(ROOT, true)
}
}
fun copyStateValues(target: BlockState, source: BlockState): BlockState {
return target
.setValue(ROOT, source.getValue(ROOT))
.setValue(BlockStateProperties.FACING, source.getValue(BlockStateProperties.FACING))
}
fun wisternCanSurvive(state: BlockState, level: LevelReader, pos: BlockPos): Boolean {
if (state.getValue(ROOT)) {
val facing = state.getValue(BlockStateProperties.FACING)
val targetPos = pos.relative(facing.opposite)
val directionState = level.getBlockState(targetPos)
return directionState.isFaceSturdy(level, targetPos, facing)
} else {
val topState = level.getBlockState(pos.relative(Direction.UP))
return topState.`is`(CobblemonBlocks.WISTENSU) || topState.`is`(CobblemonBlocks.WISTENSU_VINE)
}
}
fun wisternUpdateShape(state: BlockState, direction: Direction, neighborState: BlockState, level: LevelAccessor, pos: BlockPos, neighborPos: BlockPos, block: Block): BlockState? {
if (!wisternCanSurvive(state, level, pos)) {
level.scheduleTick(pos, block, 1)
}
if (direction == Direction.UP &&
(neighborState.`is`(CobblemonBlocks.WISTENSU) || neighborState.`is`(CobblemonBlocks.WISTENSU_VINE))) {
return state
.setValue(ROOT, false)
.setValue(BlockStateProperties.FACING, Direction.DOWN)
}
return null
}
companion object {
val ROOT = BooleanProperty.create("root")
}
}
@@ -0,0 +1,114 @@
/*
* 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.decor
import com.cobblemon.mod.common.CobblemonBlocks
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.GrowingPlantHeadBlock
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.phys.shapes.VoxelShape
import kotlin.math.min
//TODO: Root/connection shit
class WistensuFlowerHeadBlock(properties: Properties?) : GrowingPlantHeadBlock(properties, Direction.DOWN, SHAPE, false, 0.1), WistensuFlowerBlock {
companion object {
val CODEC: MapCodec<WistensuFlowerHeadBlock> = RecordCodecBuilder.mapCodec {
it.group(propertiesCodec()).apply(it, ::WistensuFlowerHeadBlock)
}
val SHAPE: VoxelShape = box(1.0, 2.0, 1.0, 15.0, 16.0, 15.0)
}
override fun codec(): MapCodec<WistensuFlowerHeadBlock> = CODEC
override fun getBlocksToGrowWhenBonemealed(random: RandomSource): Int {
var d = 1.0
var i = 0
while (random.nextDouble() < d) {
d *= 0.826
++i
}
return i
}
override fun canGrowInto(state: BlockState): Boolean {
return state.isAir
}
override fun getBodyBlock(): Block {
return CobblemonBlocks.WISTENSU_VINE
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
super.createBlockStateDefinition(builder)
additionalBlockStateDefinition(builder)
}
override fun updateShape(
state: BlockState,
direction: Direction,
neighborState: BlockState,
level: LevelAccessor,
pos: BlockPos,
neighborPos: BlockPos
): BlockState {
val updateState = wisternUpdateShape(state, direction, neighborState, level, pos, neighborPos, this)
if (updateState != null) return updateState
if (direction == Direction.DOWN &&
(neighborState.`is`(CobblemonBlocks.WISTENSU) || neighborState.`is`(CobblemonBlocks.WISTENSU_VINE))) {
return updateBodyAfterConvertedFromHead(state, bodyBlock.defaultBlockState())
}
return state
}
override fun getStateForPlacement(context: BlockPlaceContext): BlockState {
val defaultState = super.getStateForPlacement(context)!!
return adjustStateForPlacement(context, defaultState)
}
override fun getGrowIntoState(state: BlockState, random: RandomSource): BlockState {
return super.getGrowIntoState(state, random)
.setValue(WistensuFlowerBlock.ROOT, false)
.setValue(BlockStateProperties.FACING, Direction.DOWN)
}
override fun updateBodyAfterConvertedFromHead(head: BlockState, body: BlockState): BlockState {
return copyStateValues(body, head)
}
override fun performBonemeal(level: ServerLevel, random: RandomSource, pos: BlockPos, state: BlockState) {
var blockPos = pos.relative(growthDirection)
var i = min(state.getValue(AGE), MAX_AGE)
val j = getBlocksToGrowWhenBonemealed(random)
var currentState = state
for (k in 0..<j) {
if (!canGrowInto(level.getBlockState(blockPos))) break
level.setBlockAndUpdate(blockPos, getGrowIntoState(currentState, random))
currentState = level.getBlockState(blockPos)
blockPos = blockPos.relative(growthDirection)
i = min(i + 1, MAX_AGE)
}
}
override fun canSurvive(state: BlockState, level: LevelReader, pos: BlockPos): Boolean {
return wisternCanSurvive(state, level, pos)
}
}
@@ -0,0 +1,77 @@
/*
* 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.decor
import com.cobblemon.mod.common.CobblemonBlocks
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.GrowingPlantBodyBlock
import net.minecraft.world.level.block.GrowingPlantHeadBlock
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.phys.shapes.VoxelShape
//TODO: Root/connection shit
class WistensuFlowerVineBlock(properties: Properties?) : GrowingPlantBodyBlock(properties, Direction.DOWN, SHAPE, false), WistensuFlowerBlock
{
companion object {
val CODEC: MapCodec<WistensuFlowerVineBlock> = RecordCodecBuilder.mapCodec {
it.group(propertiesCodec()).apply(it, ::WistensuFlowerVineBlock)
}
val SHAPE: VoxelShape = box(1.0, 0.0, 1.0, 15.0, 16.0, 15.0)
}
override fun codec(): MapCodec<WistensuFlowerVineBlock> = CODEC
override fun getHeadBlock(): GrowingPlantHeadBlock {
return CobblemonBlocks.WISTENSU
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
super.createBlockStateDefinition(builder)
additionalBlockStateDefinition(builder)
}
override fun updateShape(
state: BlockState,
direction: Direction,
neighborState: BlockState,
level: LevelAccessor,
pos: BlockPos,
neighborPos: BlockPos
): BlockState {
val updateState = wisternUpdateShape(state, direction, neighborState, level, pos, neighborPos, this)
if (updateState != null) return updateState
if (direction == Direction.DOWN &&
!neighborState.`is`(CobblemonBlocks.WISTENSU) && !neighborState.`is`(CobblemonBlocks.WISTENSU_VINE)) {
return updateHeadAfterConvertedFromBody(state, headBlock.getStateForPlacement(level))
}
return state
}
override fun getStateForPlacement(context: BlockPlaceContext): BlockState {
val defaultState = super.getStateForPlacement(context)!!
return adjustStateForPlacement(context, defaultState)
}
override fun updateHeadAfterConvertedFromBody(head: BlockState, body: BlockState): BlockState {
return copyStateValues(body, head)
}
override fun canSurvive(state: BlockState, level: LevelReader, pos: BlockPos): Boolean {
return wisternCanSurvive(state, level, pos)
}
}
@@ -0,0 +1,46 @@
/*
* 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 com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.decor.MistleafFlowerBlock
import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
class MistleafFlowerBlockEntity(pos: BlockPos, state: BlockState): BlockEntity(CobblemonBlockEntities.MISTLEAF_FLOWER, pos, state) {
companion object {
fun serverTick(level: Level, pos: BlockPos, state: BlockState, mistleafFlowerBlockEntity: MistleafFlowerBlockEntity) {
if (level.isClientSide) return
if (state.block !is MistleafFlowerBlock) return
val glowing = state.getValue(MistleafFlowerBlock.GLOWING)
val wantedState = when (state.`is`(CobblemonBlocks.MISTLEAF)) {
//The light level and comparator output increases on odds from New to Full, and decreases on the evens from Full to New
((level.dayTime().toInt().mod(24000) in 12542..23459) && level.moonPhase == 4) -> 1 //New Moon
((level.dayTime().toInt().mod(24000) in 12542..23459) && level.moonPhase == 5) -> 3 //Waxing Crescent
((level.dayTime().toInt().mod(24000) in 12542..23459) && level.moonPhase == 6) -> 5 //First Quarter
((level.dayTime().toInt().mod(24000) in 12542..23459) && level.moonPhase == 7) -> 7 //Waxing Gibbous
((level.dayTime().toInt().mod(24000) in 12542..23459) && level.moonPhase == 0) -> 8 //Full Moon
((level.dayTime().toInt().mod(24000) in 12542..23459) && level.moonPhase == 1) -> 6 //Waning Gibbous
((level.dayTime().toInt().mod(24000) in 12542..23459) && level.moonPhase == 2) -> 4 // Third Quarter
((level.dayTime().toInt().mod(24000) in 12542..23459) && level.moonPhase == 3) -> 2 //Waning Crescent
else -> 0 //Daytime, and likely dimensions with no concept of day/night cycle or moon phase
}
if (glowing != wantedState) {
level.setBlock(pos, state.setValue(MistleafFlowerBlock.GLOWING, wantedState), Block.UPDATE_ALL)
}
}
}
}
@@ -171,11 +171,7 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
fun attemptSpawn(player: Player) {
val cause = SpawnCause(spawner = spawner, entity = player)
val zoneInput = spawner.getZoneInput(cause)
val spawnAction = spawner.calculateSpawnActionsForArea(zoneInput, 1).firstOrNull()
if (spawnAction == null) {
return
}
val spawnAction = spawner.calculateSpawnActionsForArea(zoneInput, 1).firstOrNull() ?: return
CobblemonEvents.POKE_SNACK_SPAWN_POKEMON_PRE.postThen(
PokeSnackSpawnPokemonEvent.Pre(this, spawnAction),
@@ -334,8 +334,6 @@ class TMMachineBlockEntity(pos: BlockPos, state: BlockState) :
level?.updateNeighborsAt(blockPos, currentState.block)
}
override fun stillValid(player: Player): Boolean = tmMachineInventory.stillValid(player)
override fun canPlaceItem(slot: Int, stack: ItemStack): Boolean = tmMachineInventory.canPlaceItem(slot, stack)
override fun canTakeItem(target: Container, slot: Int, stack: ItemStack): Boolean =
@@ -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.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.decor.TerrainPlantBlock
import net.minecraft.core.BlockPos
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
class TerrainPlantBlockEntity(pos: BlockPos, state: BlockState): BlockEntity(CobblemonBlockEntities.TERRAIN_PLANT, pos, state) {
companion object {
fun serverTick(level: Level, pos: BlockPos, state: BlockState, terrainPlantBlockEntity: TerrainPlantBlockEntity) {
if (level.isClientSide) return
if (state.block !is TerrainPlantBlock) return
val glowing = state.getValue(TerrainPlantBlock.GLOWING)
val wantedState = if (state.`is`(CobblemonBlocks.VOLTACONIA)) level.isThundering
else if (state.`is`(CobblemonBlocks.VERDROOT)) level.isRaining && !level.isThundering
else null // We dont control glowing here
if (wantedState != null && glowing != wantedState) {
level.setBlock(pos, state.setValue(TerrainPlantBlock.GLOWING, wantedState), Block.UPDATE_CLIENTS)
}
}
}
}
@@ -0,0 +1,133 @@
/*
* 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.general
import com.cobblemon.mod.common.util.rotateShape
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.LevelReader
import net.minecraft.world.level.block.*
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.HorizontalDirectionalBlock.FACING
import net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING
import net.minecraft.world.level.block.state.properties.IntegerProperty
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
import kotlin.math.min
class MintLitterBlock(properties: Properties?) : Block(properties) {
init {
registerDefaultState(stateDefinition.any()
.setValue(FACING, Direction.NORTH)
.setValue(AMOUNT, 1))
}
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
val blockState = context.getLevel().getBlockState(context.getClickedPos())
return if (blockState.`is`(this)) blockState.setValue<Int?, Int?>(
AMOUNT,
min(4, blockState.getValue<Int?>(AMOUNT) as Int + 1)
) as BlockState else this.defaultBlockState().setValue<Direction?, Direction?>(
FACING,
context.getHorizontalDirection().getOpposite()
) as BlockState
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(FACING)
builder.add(AMOUNT)
}
override fun updateShape(
state: BlockState,
direction: Direction?,
neighborState: BlockState?,
level: LevelAccessor?,
pos: BlockPos?,
neighborPos: BlockPos?
): BlockState {
return if (!state.canSurvive(level, pos)) Blocks.AIR.defaultBlockState() else super.updateShape(
state,
direction,
neighborState,
level,
pos,
neighborPos
)
}
override fun canSurvive(state: BlockState?, level: LevelReader, pos: BlockPos): Boolean {
val posBelow = pos.below()
return level.getBlockState(posBelow).isFaceSturdy(level, posBelow, Direction.UP)
}
override fun propagatesSkylightDown(state: BlockState, level: BlockGetter?, pos: BlockPos?): Boolean {
return state.getFluidState().isEmpty()
}
public override fun canBeReplaced(state: BlockState, useContext: BlockPlaceContext): Boolean {
return if (!useContext.isSecondaryUseActive && useContext.itemInHand.`is`(this.asItem()) && state.getValue(
AMOUNT
) <= MAX_AMOUNT
) true else super.canBeReplaced(state, useContext)
}
@Deprecated("Deprecated in Java")
override fun rotate(state: BlockState, rotation: Rotation): BlockState {
return state.setValue(HORIZONTAL_FACING, rotation.rotate(state.getValue(HORIZONTAL_FACING)))
}
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape? {
val litterBoxes = when (state.getValue(FACING)) {
Direction.SOUTH -> SOUTH_SHAPES
Direction.WEST -> WEST_SHAPES
Direction.EAST -> EAST_SHAPES
else -> NORTH_SHAPES
}
var litterBox = litterBoxes[state.getValue(AMOUNT)]
return litterBox
}
companion object {
val CODEC: MapCodec<MintLitterBlock> = RecordCodecBuilder.mapCodec {
it.group(
propertiesCodec()
).apply(it, ::MintLitterBlock) }
val AMOUNT = IntegerProperty.create("amount", 1, 4)
const val MAX_AMOUNT: Int = 4
private val NORTH_SHAPES = listOf(
Shapes.box(0.0, 0.0, 0.0, 1.0, 0.125, 1.0),
Shapes.box(0.0, 0.0, 0.0, 0.5, 0.0625, 0.5),
Shapes.box(0.0, 0.0, 0.0, 0.5, 0.0625, 1.0),
Shapes.or(
Shapes.box(0.0, 0.0, 0.0, 0.5, 0.0625, 1.0),
Shapes.box(0.5, 0.0, 0.5, 1.0, 0.0625, 1.0)
),
Shapes.box(0.0, 0.0, 0.0, 1.0, 0.0625, 1.0)
)
private val SOUTH_SHAPES = createShapes(Direction.SOUTH)
private val WEST_SHAPES = createShapes(Direction.WEST)
private val EAST_SHAPES = createShapes(Direction.EAST)
private fun createShapes(to: Direction): List<VoxelShape> {
return NORTH_SHAPES.map { rotateShape(Direction.NORTH, to, it) }
}
}
}
@@ -391,7 +391,7 @@ object CobblemonClient {
CobblemonBlocks.X_SP_ATK,
CobblemonBlocks.X_SP_DEF,
CobblemonBlocks.X_SPEED,
CobblemonBlocks.TM_MACHINE,
CobblemonBlocks.TM_MACHINE,
CobblemonBlocks.GALARICA_CUFF,
CobblemonBlocks.GALARICA_WREATH,
@@ -415,7 +415,108 @@ object CobblemonClient {
CobblemonBlocks.NEVER_MELT_ICE,
CobblemonBlocks.WIDE_LENS,
CobblemonBlocks.ZOOM_LENS,
CobblemonBlocks.SCOPE_LENS
CobblemonBlocks.SCOPE_LENS,
CobblemonBlocks.MOOMOO_MILK,
CobblemonBlocks.MEDICINAL_BREW,
CobblemonBlocks.TERRAIN_EXTENDER,
CobblemonBlocks.RED_MINT_LEAF_LITTER,
CobblemonBlocks.POTTED_RED_MINT,
CobblemonBlocks.BLUE_MINT_LEAF_LITTER,
CobblemonBlocks.POTTED_BLUE_MINT,
CobblemonBlocks.CYAN_MINT_LEAF_LITTER,
CobblemonBlocks.POTTED_CYAN_MINT,
CobblemonBlocks.PINK_MINT_LEAF_LITTER,
CobblemonBlocks.POTTED_PINK_MINT,
CobblemonBlocks.GREEN_MINT_LEAF_LITTER,
CobblemonBlocks.POTTED_GREEN_MINT,
CobblemonBlocks.WHITE_MINT_LEAF_LITTER,
CobblemonBlocks.POTTED_WHITE_MINT,
CobblemonBlocks.LOBAILA,
CobblemonBlocks.POMOHANA,
CobblemonBlocks.PAUVILLEA,
CobblemonBlocks.WISTENSU,
CobblemonBlocks.WISTENSU_VINE,
CobblemonBlocks.ELECTRIC_SEED,
CobblemonBlocks.VOLTACONIA,
CobblemonBlocks.GRASSY_SEED,
CobblemonBlocks.VERDROOT,
CobblemonBlocks.MISTY_SEED,
CobblemonBlocks.MISTLEAF,
CobblemonBlocks.PSYCHIC_SEED,
CobblemonBlocks.LUCIBELL,
CobblemonBlocks.POTTED_AGUAV_BERRY,
CobblemonBlocks.POTTED_APICOT_BERRY,
CobblemonBlocks.POTTED_ASPEAR_BERRY,
CobblemonBlocks.POTTED_BABIRI_BERRY,
CobblemonBlocks.POTTED_BELUE_BERRY,
CobblemonBlocks.POTTED_BLUK_BERRY,
CobblemonBlocks.POTTED_CHARTI_BERRY,
CobblemonBlocks.POTTED_CHERI_BERRY,
CobblemonBlocks.POTTED_CHESTO_BERRY,
CobblemonBlocks.POTTED_CHILAN_BERRY,
CobblemonBlocks.POTTED_CHOPLE_BERRY,
CobblemonBlocks.POTTED_COBA_BERRY,
CobblemonBlocks.POTTED_COLBUR_BERRY,
CobblemonBlocks.POTTED_CORNN_BERRY,
CobblemonBlocks.POTTED_CUSTAP_BERRY,
CobblemonBlocks.POTTED_DURIN_BERRY,
CobblemonBlocks.POTTED_EGGANT_BERRY,
CobblemonBlocks.POTTED_ENIGMA_BERRY,
CobblemonBlocks.POTTED_FIGY_BERRY,
CobblemonBlocks.POTTED_GANLON_BERRY,
CobblemonBlocks.POTTED_GREPA_BERRY,
CobblemonBlocks.POTTED_HABAN_BERRY,
CobblemonBlocks.POTTED_HONDEW_BERRY,
CobblemonBlocks.POTTED_HOPO_BERRY,
CobblemonBlocks.POTTED_IAPAPA_BERRY,
CobblemonBlocks.POTTED_JABOCA_BERRY,
CobblemonBlocks.POTTED_KASIB_BERRY,
CobblemonBlocks.POTTED_KEBIA_BERRY,
CobblemonBlocks.POTTED_KEE_BERRY,
CobblemonBlocks.POTTED_KELPSY_BERRY,
CobblemonBlocks.POTTED_LANSAT_BERRY,
CobblemonBlocks.POTTED_LEPPA_BERRY,
CobblemonBlocks.POTTED_LIECHI_BERRY,
CobblemonBlocks.POTTED_LUM_BERRY,
CobblemonBlocks.POTTED_MAGOST_BERRY,
CobblemonBlocks.POTTED_MAGO_BERRY,
CobblemonBlocks.POTTED_MARANGA_BERRY,
CobblemonBlocks.POTTED_MICLE_BERRY,
CobblemonBlocks.POTTED_NANAB_BERRY,
CobblemonBlocks.POTTED_NOMEL_BERRY,
CobblemonBlocks.POTTED_OCCA_BERRY,
CobblemonBlocks.POTTED_ORAN_BERRY,
CobblemonBlocks.POTTED_PAMTRE_BERRY,
CobblemonBlocks.POTTED_PASSHO_BERRY,
CobblemonBlocks.POTTED_PAYAPA_BERRY,
CobblemonBlocks.POTTED_PECHA_BERRY,
CobblemonBlocks.POTTED_PERSIM_BERRY,
CobblemonBlocks.POTTED_PETAYA_BERRY,
CobblemonBlocks.POTTED_PINAP_BERRY,
CobblemonBlocks.POTTED_POMEG_BERRY,
CobblemonBlocks.POTTED_QUALOT_BERRY,
CobblemonBlocks.POTTED_RABUTA_BERRY,
CobblemonBlocks.POTTED_RAWST_BERRY,
CobblemonBlocks.POTTED_RAZZ_BERRY,
CobblemonBlocks.POTTED_RINDO_BERRY,
CobblemonBlocks.POTTED_ROSELI_BERRY,
CobblemonBlocks.POTTED_ROWAP_BERRY,
CobblemonBlocks.POTTED_SALAC_BERRY,
CobblemonBlocks.POTTED_SHUCA_BERRY,
CobblemonBlocks.POTTED_SITRUS_BERRY,
CobblemonBlocks.POTTED_SPELON_BERRY,
CobblemonBlocks.POTTED_STARF_BERRY,
CobblemonBlocks.POTTED_TAMATO_BERRY,
CobblemonBlocks.POTTED_TANGA_BERRY,
CobblemonBlocks.POTTED_TOUGA_BERRY,
CobblemonBlocks.POTTED_WACAN_BERRY,
CobblemonBlocks.POTTED_WATMEL_BERRY,
CobblemonBlocks.POTTED_WEPEAR_BERRY,
CobblemonBlocks.POTTED_WIKI_BERRY,
CobblemonBlocks.POTTED_YACHE_BERRY
)
this.createBoatModelLayers()
@@ -475,7 +475,7 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
val locators = particleData.locatorResolver(locatorStates).filter(::isLocatorVisible)
if (particleData.chance > random.nextDouble()) {
locators.forEach { locator ->
repeat(particleData.amount) {
repeat(particleData.amount()) {
runtime.resolve("q.particle('${particleData.particle}', '$locator')".asExpressionLike())
}
}
@@ -485,7 +485,7 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
is ParticleData.MinecraftParticle -> {
if (particleData.chance > random.nextDouble()) {
val box = currentEntity.boundingBox
repeat(particleData.amount) {
repeat(particleData.amount()) {
val x = box.minX + (box.maxX - box.minX) * random.nextDouble()
val y = box.minY + (box.maxY - box.minY) * random.nextDouble()
val z = box.minZ + (box.maxZ - box.minZ) * random.nextDouble()
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.lang
import java.awt.Color
import net.minecraft.client.Minecraft
@@ -328,7 +329,7 @@ class HabitatSpawnEditorGUI(
private fun parseSpecies(value: String): Species? {
val lowered = value.lowercase()
pokemonSpeciesByTranslatedName[lowered]?.let { return it }
return runCatching { PokemonSpecies.getByName(lowered) }.getOrNull()
return runCatching { PokemonSpecies.getByIdentifier(lowered.asIdentifierDefaultingNamespace()) }.getOrNull()
}
private fun parsePhases(raw: String): IntRanges? {
@@ -21,7 +21,6 @@ import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.locale.Language
@@ -36,7 +35,7 @@ internal fun describePokemonProperties(properties: PokemonProperties): MutableCo
val descriptors = mutableListOf<MutableComponent>()
properties.species?.let { PokemonSpecies.getByIdentifier(cobblemonResource(it)) }?.let {
properties.species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }?.let {
descriptors.add(it.translatedName.plainCopy().green())
}
properties.gender?.let {
@@ -136,7 +135,7 @@ private fun describeStringSpeciesFeature(property: StringSpeciesFeature): Mutabl
return null
}
val value = PokemonSpecies.getByIdentifier(cobblemonResource(property.value))?.translatedName?.plainCopy()
val value = PokemonSpecies.getByIdentifier(property.value.asIdentifierDefaultingNamespace())?.translatedName?.plainCopy()
?: Component.literal(property.value)
return lang(key, value.green())
@@ -18,7 +18,7 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.DummyEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.itemRegistry
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.Minecraft
@@ -105,7 +105,7 @@ fun renderTradeEvolution(tradeEvolution: TradeEvolution): RenderEvolutionData? {
if (species == null) {
tooltips.add(lang("ui.pokedex.evolution.trade.tooltip.with_any_species"))
} else {
PokemonSpecies.getByIdentifier(cobblemonResource(species))?.let {
PokemonSpecies.getByIdentifier(species.asIdentifierDefaultingNamespace())?.let {
tooltips.add(lang("ui.pokedex.evolution.trade.tooltip.with_species", it.translatedName.green()))
}
}
@@ -1041,7 +1041,10 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
// Scroll to move if moves list contains held TM move
if (tmList.get().contains(heldStackTm)) {
val moveListIndex = tmList.get().indexOf(heldStackTm)
movesScrollingList.scrollAmount = (if (moveListIndex == tmList.get().lastIndex) 1.0 else (moveListIndex / tmList.get().size.toDouble()))* movesScrollingList.maxScroll
movesScrollingList.scrollAmount = movesScrollingList.maxScroll * when (moveListIndex) {
tmList.get().lastIndex -> 1.0
else -> (moveListIndex / tmList.get().size.toDouble())
}
}
}
}
@@ -545,12 +545,11 @@ abstract class PosableState : Schedulable {
primaryAnimation?.animation?.applyEffects(entity, this, previousSeconds, newSeconds)
currentModel?.let { model ->
val pose = currentPose?.let { model.poses[it] }
// Effects start playing from pose animations as long as the intensity is above 0.5. Pretty sloppy honestly.
pose?.animations
?.asSequence()
?.filter { it.condition(this) }
?.forEach {
it.applyEffects(entity, this, previousSeconds, newSeconds)
}
?.filter { shouldIdleRun(it, 0.5F) && it.condition(this) }
?.forEach { it.applyEffects(entity, this, previousSeconds, newSeconds) }
}
}
@@ -1,72 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
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.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class LuxioModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("luxio")
override val head = getPart("head")
override val foreLeftLeg = getPart("front_leg_left")
override val foreRightLeg = getPart("front_leg_right")
override val hindLeftLeg = getPart("back_leg_left")
override val hindRightLeg = getPart("back_leg_right")
override var portraitScale = 1.8F
override var portraitTranslation = Vec3(-0.6, -0.25, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
override fun registerPoses() {
// val blink = quirk { bedrockStateful("luxio", "blink") }
sleep = registerPose(
poseType = PoseType.SLEEP,
animations = arrayOf(bedrock("luxio", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STATIONARY_POSES,
// quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("luxio", "idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
// quirks = arrayOf(blink),
animations = arrayOf(
QuadrupedWalkAnimation(this, periodMultiplier = 1.1F),
singleBoneLook(),
bedrock("luxio", "idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("luxio", "faint") else null
}
@@ -1,67 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
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.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class LuxrayModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("luxray")
override val head = getPart("head")
override val foreLeftLeg = getPart("front_leg_left")
override val foreRightLeg = getPart("front_leg_right")
override val hindLeftLeg = getPart("back_leg_left")
override val hindRightLeg = getPart("back_leg_right")
override var portraitScale = 1.8F
override var portraitTranslation = Vec3(-0.9, 0.6, 0.0)
override var profileScale = 0.66F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
override fun registerPoses() {
// val blink = quirk { bedrockStateful("luxray", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STATIONARY_POSES,
// quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("luxray", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
// quirks = arrayOf(blink),
animations = arrayOf(
QuadrupedWalkAnimation(this, periodMultiplier = 1.1F),
bedrock("luxray", "ground_idle"),
singleBoneLook()
// bedrock("luxray", "idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("luxray", "faint") else null
}
@@ -1,66 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
import com.cobblemon.mod.common.client.render.models.blockbench.animation.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.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ShinxModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
override val rootPart = root.registerChildWithAllChildren("shinx")
override val head = getPart("head")
override val foreLeftLeg = getPart("leg_left")
override val foreRightLeg = getPart("leg_right")
override val hindLeftLeg = getPart("back_leg_left")
override val hindRightLeg = getPart("back_leg_right")
override var portraitScale = 1.8F
override var portraitTranslation = Vec3(-0.6, -0.25, 0.0)
override var profileScale = 0.66F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
override fun registerPoses() {
// val blink = quirk { bedrockStateful("shinx", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STATIONARY_POSES,
// quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("shinx", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
// quirks = arrayOf(blink),
animations = arrayOf(
QuadrupedWalkAnimation(this, periodMultiplier = 1.1F),
singleBoneLook(),
bedrock("shinx", "ground_idle")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("shinx", "faint") else null
}
@@ -1,70 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ChesnaughtModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("chesnaught")
override val head = getPart("head")
override val rightArm = getPart("arm_right")
override val leftArm = getPart("arm_left")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 2.2F
override var portraitTranslation = Vec3(-1.0, 1.65, 0.0)
override var profileScale = 0.6F
override var profileTranslation = Vec3(0.0, 0.85, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
override val cryAnimation = CryProvider { bedrockStateful("chesnaught", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("chesnaught", "blink")}
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("chesnaught", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
BimanualSwingAnimation(this),
BipedWalkAnimation(this),
bedrock("chesnaught", "ground_idle")
)
)
}
}
@@ -1,70 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class ChespinModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("chespin")
override val head = getPart("head")
override val rightArm = getPart("arm_right")
override val leftArm = getPart("arm_left")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 2.03F
override var portraitTranslation = Vec3(-0.12, -0.44, 0.0)
override var profileScale = 0.77F
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
override val cryAnimation = CryProvider { bedrockStateful("chespin", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("chespin", "blink")}
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("chespin", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("chespin", "ground_walk")
)
)
sleep = registerPose(
poseType = PoseType.SLEEP,
transformTicks = 10,
animations = arrayOf(bedrock("chespin", "sleep"))
)
}
}
@@ -1,118 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class FroakieModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("froakie")
override val head = getPart("head")
override val rightArm = getPart("arm_right")
override val leftArm = getPart("arm_left")
override val rightLeg = getPart("leg_right")
override val leftLeg = getPart("leg_left")
override var portraitScale = 1.86F
override var portraitTranslation = Vec3(-0.25, -0.51, 0.0)
override var profileScale = 0.75F
override var profileTranslation = Vec3(0.0, 0.56, 0.0)
lateinit var sleep: Pose
lateinit var standing: Pose
lateinit var float: Pose
lateinit var swim: Pose
lateinit var walk: Pose
lateinit var battleidle: Pose
override val cryAnimation = CryProvider { bedrockStateful("froakie", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("froakie", "blink")}
sleep = registerPose(
poseType = PoseType.SLEEP,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(bedrock("froakie", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STATIONARY_POSES - PoseType.FLOAT,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("froakie", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseType = PoseType.WALK,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("froakie", "ground_walk")
)
)
float = registerPose(
poseName = "swim_idle",
poseTypes = setOf(PoseType.FLOAT, PoseType.HOVER),
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("froakie", "water_idle")
)
)
swim = registerPose(
poseName = "swim",
poseTypes = setOf(PoseType.SWIM, PoseType.FLY),
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("froakie", "water_swim")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("froakie", "battle_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, battleidle, swim, float, sleep)) bedrockStateful("froakie", "faint") else null
}
@@ -1,118 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class FrogadierModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("frogadier")
override val head = getPart("head")
override val rightArm = getPart("arm_right")
override val leftArm = getPart("arm_left")
override val rightLeg = getPart("leg_right")
override val leftLeg = getPart("leg_left")
override var portraitScale = 1.9F
override var portraitTranslation = Vec3(-0.1, 1.4, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var sleep: Pose
lateinit var standing: Pose
lateinit var float: Pose
lateinit var swim: Pose
lateinit var walk: Pose
lateinit var battleidle: Pose
override val cryAnimation = CryProvider { bedrockStateful("frogadier", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("frogadier", "blink")}
sleep = registerPose(
poseType = PoseType.SLEEP,
transformTicks = 10,
quirks = arrayOf(blink),
animations = arrayOf(bedrock("frogadier", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STATIONARY_POSES - PoseType.FLOAT,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("frogadier", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseType = PoseType.WALK,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("frogadier", "ground_walk")
)
)
float = registerPose(
poseName = "swim_idle",
poseTypes = setOf(PoseType.FLOAT, PoseType.HOVER),
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("frogadier", "water_idle")
)
)
swim = registerPose(
poseName = "swim",
poseTypes = setOf(PoseType.SWIM, PoseType.FLY),
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("frogadier", "water_swim")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
animations = arrayOf(
singleBoneLook(),
bedrock("frogadier", "battle_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, battleidle, swim, float, sleep)) bedrockStateful("frogadier", "faint") else null
}
@@ -1,142 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.isBattling
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class GreninjaModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("greninja")
override val head = getPart("head")
override val rightArm = getPart("arm_right")
override val leftArm = getPart("arm_left")
override val rightLeg = getPart("leg_right")
override val leftLeg = getPart("leg_left")
val shurikenright = getPart("hand_shuriken_right")
val shurikenleft = getPart("hand_shuriken_left")
override var portraitScale = 2.2F
override var portraitTranslation = Vec3(-0.1, 1.34, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var sleep: Pose
lateinit var standing: Pose
lateinit var float: Pose
lateinit var swim: Pose
lateinit var walk: Pose
lateinit var battleidle: Pose
override val cryAnimation = CryProvider { bedrockStateful("greninja", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("greninja", "blink")}
sleep = registerPose(
poseType = PoseType.SLEEP,
transformTicks = 10,
transformedParts = arrayOf(
shurikenleft.createTransformation().withVisibility(visibility = false),
shurikenright.createTransformation().withVisibility(visibility = false)
),
animations = arrayOf(bedrock("greninja", "sleep"))
)
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STATIONARY_POSES - PoseType.FLOAT,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
transformedParts = arrayOf(
shurikenleft.createTransformation().withVisibility(visibility = false),
shurikenright.createTransformation().withVisibility(visibility = false)
),
animations = arrayOf(
singleBoneLook(),
bedrock("greninja", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseType = PoseType.WALK,
transformTicks = 10,
quirks = arrayOf(blink),
transformedParts = arrayOf(
shurikenleft.createTransformation().withVisibility(visibility = false),
shurikenright.createTransformation().withVisibility(visibility = false)
),
animations = arrayOf(
singleBoneLook(),
bedrock("greninja", "ground_walk")
)
)
float = registerPose(
poseName = "swim_idle",
poseTypes = setOf(PoseType.FLOAT, PoseType.HOVER),
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
transformedParts = arrayOf(
shurikenleft.createTransformation().withVisibility(visibility = false),
shurikenright.createTransformation().withVisibility(visibility = false)
),
animations = arrayOf(
singleBoneLook(),
bedrock("greninja", "water_idle")
)
)
swim = registerPose(
poseName = "swim",
poseTypes = setOf(PoseType.SWIM, PoseType.FLY),
transformTicks = 10,
quirks = arrayOf(blink),
condition = { !it.isBattling },
transformedParts = arrayOf(
shurikenleft.createTransformation().withVisibility(visibility = false),
shurikenright.createTransformation().withVisibility(visibility = false)
),
animations = arrayOf(
singleBoneLook(),
bedrock("greninja", "water_swim")
)
)
battleidle = registerPose(
poseName = "battle_idle",
poseTypes = PoseType.STATIONARY_POSES,
transformTicks = 10,
quirks = arrayOf(blink),
condition = { it.isBattling },
transformedParts = arrayOf(
shurikenleft.createTransformation().withVisibility(visibility = false),
shurikenright.createTransformation().withVisibility(visibility = false)
),
animations = arrayOf(
singleBoneLook(),
bedrock("greninja", "battle_idle")
)
)
}
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, battleidle, swim, float, sleep)) bedrockStateful("greninja", "faint") else null
}
@@ -1,73 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class QuilladinModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("quilladin")
override val head = getPart("torso")
override val rightArm = getPart("arm_right")
override val leftArm = getPart("arm_left")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 2F
override var portraitTranslation = Vec3(-0.3, 0.1, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
lateinit var sleep: Pose
override val cryAnimation = CryProvider { bedrockStateful("quilladin", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("quilladin", "blink")}
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("quilladin", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = MOVING_POSES,
quirks = arrayOf(blink),
animations = arrayOf(
singleBoneLook(),
bedrock("quilladin", "ground_walk")
)
)
sleep = registerPose(
poseType = PoseType.SLEEP,
transformTicks = 10,
animations = arrayOf(bedrock("quilladin", "sleep"))
)
}
}
@@ -29,7 +29,7 @@ class VivillonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, B
override var portraitTranslation = Vec3(-0.3, 0.2, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3(0.1, 0.8, 0.0)
override var profileTranslation = Vec3(0.0, 0.8, 0.0)
lateinit var standing: Pose
lateinit var walk: Pose
@@ -311,9 +311,6 @@ object VaryingModelRepository {
inbuilt("morelull", :: MorelullModel)
inbuilt("shiinotic", :: ShiinoticModel)
inbuilt("spiritomb", :: SpiritombModel)
inbuilt("chespin", :: ChespinModel)
inbuilt("quilladin", :: QuilladinModel)
inbuilt("chesnaught", :: ChesnaughtModel)
inbuilt("pineco", :: PinecoModel)
inbuilt("lotad", :: LotadModel)
inbuilt("lombre", :: LombreModel)
@@ -341,9 +338,6 @@ object VaryingModelRepository {
inbuilt("walkingwake", ::WalkingwakeModel)
inbuilt("ironleaves", ::IronleavesModel)
inbuilt("miltank", ::MiltankModel)
inbuilt("froakie", ::FroakieModel)
inbuilt("frogadier", ::FrogadierModel)
inbuilt("greninja", ::GreninjaModel)
inbuilt("grookey", ::GrookeyModel)
inbuilt("thwackey", ::ThwackeyModel)
inbuilt("rillaboom", ::RillaboomModel)
@@ -396,9 +390,6 @@ object VaryingModelRepository {
inbuilt("hoothoot", ::HoothootModel)
inbuilt("wingull", ::WingullModel)
inbuilt("pelipper", ::PelipperModel)
inbuilt("shinx", ::ShinxModel)
inbuilt("luxio", ::LuxioModel)
inbuilt("luxray", ::LuxrayModel)
inbuilt("numel", ::NumelModel)
inbuilt("roggenrola", ::RoggenrolaModel)
inbuilt("boldore", ::BoldoreModel)
@@ -319,32 +319,37 @@ class PokemonRenderer(
val clientDelegate = entity.delegate as PokemonClientDelegate
val pokemonPosition = entity.position().add(0.0, entity.bbHeight / 2.0 * clientDelegate.activeSendoutScale.toDouble(), 0.0)
val recallBallOrigin = (beamTarget as? Player)?.let { RecallArmAnimationTracker.get(it.uuid)?.beamOrigin }
var beamSourcePosition = if (recallBallOrigin != null) {
recallBallOrigin
} else if (beamTarget is EmptyPokeBallEntity) {
(beamTarget.delegate as PokeBallPosableState).locatorStates["beam"]?.transformPosition(Vec3(0.0, 0.2, 0.45)) ?: beamTarget.position()
} else {
if (beamTarget.uuid == Minecraft.getInstance().player?.uuid) {
val beamSourcePosition = when {
// cover the recall ball origin presence
recallBallOrigin != null -> recallBallOrigin
// cover the pokeball catching a specimen
beamTarget is EmptyPokeBallEntity -> (beamTarget.delegate as PokeBallPosableState)
.locatorStates["beam"]
?.transformPosition(Vec3(0.0, 0.2, 0.45)) ?: beamTarget.position()
// player recall
beamTarget.uuid == Minecraft.getInstance().player?.uuid -> {
val lookVec = beamTarget.lookAngle.yRot((PI / 2).toFloat()).multiply(1.0, 0.0, 1.0).normalize()
beamTarget.getEyePosition(partialTicks).subtract(0.0, 0.4, 0.0).subtract(lookVec.scale(0.3))
} else if (beamTarget is NPCEntity) {
}
// npc recall
beamTarget is NPCEntity -> {
val npcDelegate = beamTarget.delegate as NPCClientDelegate
val baseScale = beamTarget.renderScale * beamTarget.hitboxScale
(npcDelegate.locatorStates["beam"]?.getOrigin()?.scale(baseScale.toDouble()))
?: beamTarget.position().add(0.0, (beamTarget.bbHeight / 2.0) * baseScale, 0.0)
} else {
}
clientDelegate.sendOutPosition != null -> clientDelegate.sendOutPosition!!
// ???
else -> {
val lookVec = beamTarget.lookAngle.yRot((PI / 2 - (beamTarget.visualRotationYInDegrees - beamTarget.xRot).toRadians()).toFloat()).multiply(1.0, 0.0, 1.0).normalize()
beamTarget.getEyePosition(partialTicks).subtract(0.0, 0.7, 0.0).subtract(lookVec.scale(0.4))
}
}
if (clientDelegate.sendOutPosition != null) {
beamSourcePosition = clientDelegate.sendOutPosition!!
}
if (beamSourcePosition.distanceTo(pokemonPosition) > 20) {
return
}
if (beamSourcePosition.distanceTo(pokemonPosition) > 20) return
var newOffset = offset.scale(2.0)
// the further away the source position is, the smaller the newOffset should be. Max distance is 20 blocks
val distance = beamSourcePosition.distanceTo(entity.position())
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.command.argument
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.common.base.Splitter
import com.mojang.brigadier.StringReader
import com.mojang.brigadier.arguments.ArgumentType
@@ -38,7 +39,7 @@ class FormArgumentType : ArgumentType<FormData> {
}
speciesBeginning++
val speciesToken = reader.string.substring(speciesBeginning, formTokenBeginning)
val species = PokemonSpecies.getByName(speciesToken) ?: PokemonSpecies.species.first()
val species = PokemonSpecies.getByIdentifier(speciesToken.asIdentifierDefaultingNamespace()) ?: PokemonSpecies.species.first()
val result = species.forms.union(listOf(species.standardForm)).first { it.formOnlyShowdownId().lowercase() == formToken }
return result
}
@@ -57,7 +58,7 @@ class FormArgumentType : ArgumentType<FormData> {
curIdx++
val speciesToken = builder.input.substring(curIdx, builder.start - 1)
val species = PokemonSpecies.getByName(speciesToken) ?: PokemonSpecies.species.first()
val species = PokemonSpecies.getByIdentifier(speciesToken.asIdentifierDefaultingNamespace()) ?: PokemonSpecies.species.first()
val forms = species.forms.union(listOf(species.standardForm)).filter { it.formOnlyShowdownId().lowercase().startsWith(formToken) }
forms.forEach { str ->
builder.suggest(str.formOnlyShowdownId())
@@ -222,16 +222,16 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Spawning, lang = "shiny_rate", SERVER)
var shinyRate = 8192F
@CobblemonConfigField(Category.Pokemon, lang = "fossil_machine_alpha_chance", SERVER)
@CobblemonConfigField(Category.Spawning, lang = "fossil_machine_alpha_chance", SERVER)
var fossilMachineAlphaChance = 20
@CobblemonConfigField(Category.Pokemon, lang = "fossil_machine_shiny_chance", SERVER)
@CobblemonConfigField(Category.Spawning, lang = "fossil_machine_shiny_chance", SERVER)
var fossilMachineShinyChance = 100
@CobblemonConfigField(Category.Pokemon, lang = "honey_slather_alpha_chance", SERVER)
@CobblemonConfigField(Category.Spawning, lang = "honey_slather_alpha_chance", SERVER)
var honeySlatherAlphaChance = 100
@CobblemonConfigField(Category.Pokemon, lang = "honey_slather_shiny_chance", SERVER)
@CobblemonConfigField(Category.Spawning, lang = "honey_slather_shiny_chance", SERVER)
var honeySlatherShinyChance = 4000
@CobblemonConfigField(Category.Pokemon, lang = "shiny_notice_particles_distance", CLIENT)
@@ -392,6 +392,21 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Spawning, lang = "data_monitor_shiny_rate", SERVER)
var monitorShinyRate = 200
@CobblemonConfigField(Category.World, lang = "type_gem_max_connected", SERVER)
var typeGemMaxConnected = 16
@CobblemonConfigField(Category.World, lang = "type_gem_min_growth", SERVER)
var typeGemMinGrowth = 8
@CobblemonConfigField(Category.World, lang = "type_gem_growth_chance", SERVER)
var typeGemGrowthChance = 0.1f
@CobblemonConfigField(Category.World, lang = "type_gem_initial_expansion_cycles", SERVER)
var typeGemInitialExpansionCycles = 100
@CobblemonConfigField(Category.World, lang = "type_gem_tick_chance", SERVER)
var typeGemTickChance = 1.0f
fun clone(): CobblemonConfig {
val newConfig = CobblemonConfig()
CobblemonConfig::class.memberProperties.forEach { property ->
@@ -30,7 +30,7 @@ object CobblemonSchemas {
private val SAME: (Int, Schema) -> Schema = ::Schema
private val RESULT: DataFixerBuilder.Result = this.create()
const val DATA_VERSION = 2
const val DATA_VERSION = 3
/**
* The Cobblemon [DataFixer].
@@ -85,6 +85,8 @@ object CobblemonSchemas {
builder.addFixer(RaisedPPStagesFix(schema1))
val schema2 = builder.addSchema(2, SAME)
builder.addFixer(HypertrainIVFix(schema2))
val schema3 = builder.addSchema(3, SAME)
builder.addFixer(TypeGemGrowthTypeFix(schema3))
}
private class CobblemonDataFixerCodec<R>(private val baseCodec: Codec<R>, private val typeReference: TypeReference) : Codec<R> {
@@ -0,0 +1,101 @@
/*
* 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.datafixer.fix
import com.mojang.datafixers.DSL
import com.mojang.datafixers.DataFix
import com.mojang.datafixers.TypeRewriteRule
import com.mojang.datafixers.schemas.Schema
import com.mojang.serialization.Dynamic
import net.minecraft.util.datafix.fixes.References
/**
* Merges the old `should_grow` and `stunted` type gem cluster properties into `growth_type`.
*/
class TypeGemGrowthTypeFix(outputSchema: Schema) : DataFix(outputSchema, false) {
override fun makeRule(): TypeRewriteRule {
return fixTypeEverywhereTyped("TypeGemGrowthTypeFix", inputSchema.getType(References.CHUNK)) { chunk ->
chunk.update(DSL.remainderFinder(), ::fixChunk)
}
}
private fun fixChunk(chunk: Dynamic<*>): Dynamic<*> {
return chunk.update("sections") { sections ->
sections.createList(sections.asStream().map(::fixSection))
}
}
private fun fixSection(section: Dynamic<*>): Dynamic<*> {
return section.update("block_states") { blockStates ->
blockStates.update("palette") { palette ->
palette.createList(palette.asStream().map(::fixPaletteEntry))
}
}
}
private fun fixPaletteEntry(entry: Dynamic<*>): Dynamic<*> {
if (entry.get("Name").asString("") !in CLUSTER_IDS) return entry
return entry.update("Properties") { properties ->
if (properties.get(GROWTH_TYPE).result().isPresent) return@update properties
val shouldGrow = properties.get(SHOULD_GROW).asString(OLD_SHOULD_GROW_DEFAULT) == "true"
val stunted = properties.get(STUNTED).asString(OLD_STUNTED_DEFAULT) == "true"
properties
.remove(SHOULD_GROW)
.remove(STUNTED)
.set(GROWTH_TYPE, properties.createString(growthTypeFor(shouldGrow, stunted)))
}
}
private fun growthTypeFor(shouldGrow: Boolean, stunted: Boolean): String {
return when {
stunted -> GROWTH_TYPE_STUNTED
shouldGrow -> GROWTH_TYPE_FULL
else -> GROWTH_TYPE_NONE
}
}
companion object {
private const val SHOULD_GROW = "should_grow"
private const val STUNTED = "stunted"
private const val GROWTH_TYPE = "growth_type"
private const val OLD_SHOULD_GROW_DEFAULT = "true"
private const val OLD_STUNTED_DEFAULT = "false"
private const val GROWTH_TYPE_FULL = "full"
private const val GROWTH_TYPE_STUNTED = "stunted"
private const val GROWTH_TYPE_NONE = "none"
// ID's as they were when this fix was made.
private val CLUSTER_IDS = setOf(
"cobblemon:normal_gem_cluster",
"cobblemon:fire_gem_cluster",
"cobblemon:water_gem_cluster",
"cobblemon:electric_gem_cluster",
"cobblemon:grass_gem_cluster",
"cobblemon:ice_gem_cluster",
"cobblemon:fighting_gem_cluster",
"cobblemon:poison_gem_cluster",
"cobblemon:ground_gem_cluster",
"cobblemon:flying_gem_cluster",
"cobblemon:psychic_gem_cluster",
"cobblemon:bug_gem_cluster",
"cobblemon:rock_gem_cluster",
"cobblemon:ghost_gem_cluster",
"cobblemon:dragon_gem_cluster",
"cobblemon:dark_gem_cluster",
"cobblemon:steel_gem_cluster",
"cobblemon:fairy_gem_cluster"
)
}
}
@@ -1192,7 +1192,7 @@ open class PokemonEntity(
itemStack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND)
return InteractionResult.SUCCESS
} else if (itemStack.`is`(Items.BOWL)) {
if (pokemon.aspects.any { it.contains("mooshtank") }) {
if (pokemon.aspects.any { it.contains("mooshtank") && !it.contains("mooshtank-false") }) {
player.playSound(SoundEvents.MOOSHROOM_MILK, 1.0f, 1.0f)
// if the Mooshtank ate a Flower beforehand
if (pokemon.lastFlowerFed != ItemStack.EMPTY && pokemon.aspects.any { it.contains("mooshtank-brown") }) {
@@ -1234,7 +1234,8 @@ open class PokemonEntity(
) {
if (pokemon.aspects.any { it.contains("mooshtank-brown") }) {
player.playSound(SoundEvents.MOOSHROOM_EAT, 1.0f, 1.0f)
pokemon.lastFlowerFed = itemStack
pokemon.lastFlowerFed = itemStack.copyWithCount(1)
if (!player.isCreative && !level().isClientSide) itemStack.shrink(1)
return InteractionResult.sidedSuccess(level().isClientSide)
}
} else if (!player.isShiftKeyDown && StashHandler.interactMob(player, pokemon, itemStack)) {
@@ -2741,4 +2742,9 @@ open class PokemonEntity(
}
fun hasRider() = this.passengers.any { it is LivingEntity }
override fun playStepSound(pos: BlockPos, state: BlockState) {
if (this.pokemon.species.silenceStepSounds) return
super.playStepSound(pos, state)
}
}
@@ -26,6 +26,7 @@ object CallbackHandler {
CobblemonEvents.POKEMON_CAPTURED.subscribe { CobblemonCallbacks.run(cobblemonResource("pokemon_captured"), it.context) }
CobblemonEvents.POKEMON_ENTITY_SPAWN.subscribe { entity -> CobblemonCallbacks.run(cobblemonResource("pokemon_entity_spawn"), mutableMapOf<String, MoValue>("pokemon_entity" to entity.entity.asMoLangValue()), functions = moLangFunctionMap("pokemon" to { entity.entity.pokemon.struct })) }
CobblemonEvents.BATTLE_VICTORY.subscribe { CobblemonCallbacks.run(cobblemonResource("battle_victory"), it.context) }
CobblemonEvents.BATTLE_ENDED.subscribe { CobblemonCallbacks.run(cobblemonResource("battle_ended"), it.context) }
CobblemonEvents.POKEDEX_DATA_CHANGED_PRE.subscribe { CobblemonCallbacks.run(cobblemonResource("pokedex_data_changed_pre"), it.getContext(), it.functions) }
CobblemonEvents.POKEDEX_DATA_CHANGED_POST.subscribe { CobblemonCallbacks.run(cobblemonResource("pokedex_data_changed_post"), it.getContext()) }
CobblemonEvents.FORME_CHANGE.subscribe { CobblemonCallbacks.run(cobblemonResource("forme_change"), it.context) }
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.CobblemonSounds
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemNameBlockItem
import net.minecraft.world.item.SignApplicator
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.SignBlockEntity
import net.minecraft.world.level.block.entity.SignText
class GlowItem(block: Block, settings: Properties) : ItemNameBlockItem(block, settings), SignApplicator {
override fun tryApplyToSign(level: Level, sign: SignBlockEntity, isFront: Boolean, player: Player?): Boolean {
if (sign.updateText({ signText: SignText? -> signText!!.setHasGlowingText(true) }, isFront)) {
level.playSound(
null as Player?,
sign.blockPos,
CobblemonSounds.BRIGHT_POWDER_USE,
SoundSource.BLOCKS,
1.0f,
1.0f
)
return true
} else {
return false
}
}
}
@@ -35,14 +35,10 @@ class MedicinalLeekItem(block: MedicinalLeekBlock, settings: Properties) : ItemN
val blockHitResult2 = blockHitResult.withPosition(blockHitResult.blockPos.above())
val placeResult = this.place(BlockPlaceContext(UseOnContext(user, hand, blockHitResult2)))
val stack = user.getItemInHand(hand)
// This will always be true but just in case we change it down the line.
/*
if (!placeResult.isAccepted && this.isFood && user.canConsume(this.foodComponent?.isAlwaysEdible == true)) {
user.setCurrentHand(hand)
return TypedInteractionResult.consume(stack)
// If the leek couldn't be planted, fall back to the default item behaviour so its food component lets it be eaten
if (!placeResult.consumesAction()) {
return super.use(world, user, hand)
}
*/
return InteractionResultHolder(placeResult, stack)
}
@@ -13,10 +13,12 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.item.battle.SimpleBagItemLike
import net.minecraft.world.item.ItemNameBlockItem
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.level.block.Block
class MoomooMilk(properties: Properties) : CobblemonItem(properties), SimpleBagItemLike {
class MoomooMilk(properties: Properties, block: Block) : ItemNameBlockItem(block, properties), SimpleBagItemLike {
override val bagItem = object : BagItem {
override val itemName = "item.cobblemon.moomoo_milk"
override val returnItem = Items.GLASS_BOTTLE
@@ -19,14 +19,13 @@ import net.minecraft.world.level.Level
class WearableHatItem(override val name: String): CobblemonItem(Properties()), WearableItem {
override fun use(level: Level, player: Player, usedHand: InteractionHand): InteractionResultHolder<ItemStack> {
val itemStack = player.getItemInHand(usedHand)
val hitPokemon = player.traceFirstEntityCollision(
entityClass = PokemonEntity::class.java,
maxDistance = player.entityInteractionRange().toFloat()
)
// If the player is looking at a Pokémon within range, block the ability to swap the item onto their head
return if (player.isCrouching && hitPokemon != null && hitPokemon.isOwnedBy(player)) {
InteractionResultHolder.fail(itemStack)
} else this.swapWithEquipmentSlot(this, level, player, usedHand)
if (player.isCrouching && hitPokemon != null && hitPokemon.isOwnedBy(player)) return InteractionResultHolder.fail(player.getItemInHand(usedHand))
return this.swapStackWithEquipmentSlot(level, player, usedHand)
}
}
}
@@ -10,10 +10,18 @@ package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.resources.ResourceLocation
import net.minecraft.stats.Stats
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResultHolder
import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Equipable
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.enchantment.EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE
import net.minecraft.world.item.enchantment.EnchantmentHelper
import net.minecraft.world.level.Level
interface WearableItem: Equipable {
interface WearableItem : Equipable {
val name: String
companion object {
@@ -23,5 +31,43 @@ interface WearableItem: Equipable {
fun getModel3d(): ResourceLocation = cobblemonResource("${MODEL_PATH}/${this.name}")
fun getModel2d(): ResourceLocation = cobblemonResource(this.name)
override fun getEquipmentSlot(): EquipmentSlot { return EquipmentSlot.HEAD }
}
override fun getEquipmentSlot(): EquipmentSlot {
return EquipmentSlot.HEAD
}
/**
* Swap stack with equipment slot
* Copied from vanilla, modified to account for stackable items
* @see Equipable.swapWithEquipmentSlot
*
* @param item
* @param level
* @param player
* @param hand
* @return the interaction result holder
*/
fun swapStackWithEquipmentSlot(
level: Level,
player: Player,
hand: InteractionHand
): InteractionResultHolder<ItemStack> {
var itemStack = player.getItemInHand(hand)
val equipmentSlot = player.getEquipmentSlotForItem(itemStack)
if (!player.canUseSlot(equipmentSlot)) return InteractionResultHolder.pass(itemStack)
val slotStack = player.getItemBySlot(equipmentSlot)
if (!(!EnchantmentHelper.has(slotStack, PREVENT_ARMOR_CHANGE) || player.isCreative) || ItemStack.matches(itemStack, slotStack)) return InteractionResultHolder.fail(itemStack)
if (!level.isClientSide()) player.awardStat(Stats.ITEM_USED.get(itemStack.item))
val equipStack = itemStack.split(1)
when {
itemStack.isEmpty -> itemStack = slotStack.copyAndClear()
else -> player.addItem(slotStack.copyAndClear())
}
player.setItemSlot(equipmentSlot, equipStack)
return InteractionResultHolder.sidedSuccess(itemStack, level.isClientSide())
}
}
@@ -12,9 +12,11 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.block.TypeGemClusterBlock
import com.cobblemon.mod.common.item.AprijuiceItem
import com.cobblemon.mod.common.item.components.RideBoostsComponent
import com.cobblemon.mod.common.item.components.TMMoveComponent
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.component.DataComponents
import net.minecraft.core.registries.BuiltInRegistries
@@ -40,44 +42,111 @@ object CobblemonItemGroups {
private val ALL = arrayListOf<ItemGroupHolder>()
private val INJECTORS = hashMapOf<ResourceKey<CreativeModeTab>, (injector: Injector) -> Unit>()
@JvmStatic val BLOCKS_KEY = this.create("blocks", this::blockEntries) {
@JvmStatic
val BLOCKS_KEY = this.create("blocks", this::blockEntries) {
ItemStack(CobblemonItems.PC)
}
@JvmStatic val UTILITY_ITEMS_KEY = this.create("utility_item", this::utilityItemEntries) {
@JvmStatic
val UTILITY_ITEMS_KEY = this.create("utility_item", this::utilityItemEntries) {
ItemStack(CobblemonItems.POKE_BALL)
}
@JvmStatic val AGRICULTURE_KEY = this.create("agriculture", this::agricultureEntries) {
@JvmStatic
val AGRICULTURE_KEY = this.create("agriculture", this::agricultureEntries) {
ItemStack(CobblemonItems.MEDICINAL_LEEK)
}
@JvmStatic val ARCHAEOLOGY_KEY = this.create("archaeology", this::archaeologyEntries) {
@JvmStatic
val ARCHAEOLOGY_KEY = this.create("archaeology", this::archaeologyEntries) {
ItemStack(CobblemonItems.HELIX_FOSSIL)
}
@JvmStatic val CONSUMABLES_KEY = this.create("consumables", this::consumableEntries) {
@JvmStatic
val CONSUMABLES_KEY = this.create("consumables", this::consumableEntries) {
ItemStack(CobblemonItems.ROASTED_LEEK)
}
@JvmStatic val HELD_ITEMS_KEY = this.create("held_item", this::heldItemEntries) {
@JvmStatic
val HELD_ITEMS_KEY = this.create("held_item", this::heldItemEntries) {
ItemStack(CobblemonItems.EXP_SHARE)
}
@JvmStatic val EVOLUTION_ITEMS_KEY = this.create("evolution_item", this::evolutionItemEntries) {
@JvmStatic
val EVOLUTION_ITEMS_KEY = this.create("evolution_item", this::evolutionItemEntries) {
ItemStack(CobblemonItems.BLACK_AUGURITE)
}
@JvmStatic val BLOCKS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(BLOCKS_KEY)
@JvmStatic val UTILITY_ITEMS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(UTILITY_ITEMS_KEY)
@JvmStatic val AGRICULTURE get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(AGRICULTURE_KEY)
@JvmStatic val ARCHAEOLOGY get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(ARCHAEOLOGY_KEY)
@JvmStatic val CONSUMABLES get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(CONSUMABLES_KEY)
@JvmStatic val HELD_ITEMS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(HELD_ITEMS_KEY)
@JvmStatic val EVOLUTION_ITEMS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(EVOLUTION_ITEMS_KEY)
@JvmStatic
val TM_ITEMS_KEY = this.create("tm_item", this::tmItemEntries) {
ItemStack(CobblemonItems.BLANK_TM)
}
@JvmStatic val BUILDING_BLOCKS_INJECTIONS = this.inject(ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("building_blocks")), this::blocksInjections)
@JvmStatic val COLORED_BLOCKS_INJECTIONS = this.inject(ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("colored_blocks")), this::coloredBlocksInjections)
@JvmStatic val FUNCTIONAL_BLOCKS = this.inject(ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("functional_blocks")), this::functionalBlocksInjections)
@JvmStatic val REDSTONE_BLOCKS = this.inject(ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("redstone_blocks")), this::redstoneBlocksInjections)
@JvmStatic val FOOD_INJECTIONS = this.inject(ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("food_and_drinks")), this::foodInjections)
@JvmStatic val TOOLS_AND_UTILITIES_INJECTIONS = this.inject(ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("tools_and_utilities")), this::toolsAndUtilitiesInjections)
@JvmStatic val INGREDIENTS_INJECTIONS = this.inject(ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("ingredients")), this::ingredientsInjections)
@JvmStatic val OP_BLOCKS_INJECTIONS = this.inject(ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("op_blocks")), this::opBlocksInjections)
@JvmStatic
val BLOCKS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(BLOCKS_KEY)
@JvmStatic
val UTILITY_ITEMS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(UTILITY_ITEMS_KEY)
@JvmStatic
val AGRICULTURE get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(AGRICULTURE_KEY)
@JvmStatic
val ARCHAEOLOGY get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(ARCHAEOLOGY_KEY)
@JvmStatic
val CONSUMABLES get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(CONSUMABLES_KEY)
@JvmStatic
val HELD_ITEMS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(HELD_ITEMS_KEY)
@JvmStatic
val EVOLUTION_ITEMS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(EVOLUTION_ITEMS_KEY)
@JvmStatic
val TM_ITEMS get() = BuiltInRegistries.CREATIVE_MODE_TAB.get(TM_ITEMS_KEY)
@JvmStatic
val BUILDING_BLOCKS_INJECTIONS = this.inject(
ResourceKey.create(
BuiltInRegistries.CREATIVE_MODE_TAB.key(),
ResourceLocation.parse("building_blocks")
), this::blocksInjections
)
@JvmStatic
val COLORED_BLOCKS_INJECTIONS = this.inject(
ResourceKey.create(
BuiltInRegistries.CREATIVE_MODE_TAB.key(),
ResourceLocation.parse("colored_blocks")
), this::coloredBlocksInjections
)
@JvmStatic
val FUNCTIONAL_BLOCKS = this.inject(
ResourceKey.create(
BuiltInRegistries.CREATIVE_MODE_TAB.key(),
ResourceLocation.parse("functional_blocks")
), this::functionalBlocksInjections
)
@JvmStatic
val REDSTONE_BLOCKS = this.inject(
ResourceKey.create(
BuiltInRegistries.CREATIVE_MODE_TAB.key(),
ResourceLocation.parse("redstone_blocks")
), this::redstoneBlocksInjections
)
@JvmStatic
val FOOD_INJECTIONS = this.inject(
ResourceKey.create(
BuiltInRegistries.CREATIVE_MODE_TAB.key(),
ResourceLocation.parse("food_and_drinks")
), this::foodInjections
)
@JvmStatic
val TOOLS_AND_UTILITIES_INJECTIONS = this.inject(
ResourceKey.create(
BuiltInRegistries.CREATIVE_MODE_TAB.key(),
ResourceLocation.parse("tools_and_utilities")
), this::toolsAndUtilitiesInjections
)
@JvmStatic
val INGREDIENTS_INJECTIONS = this.inject(
ResourceKey.create(
BuiltInRegistries.CREATIVE_MODE_TAB.key(),
ResourceLocation.parse("ingredients")
), this::ingredientsInjections
)
@JvmStatic
val OP_BLOCKS_INJECTIONS = this.inject(
ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), ResourceLocation.parse("op_blocks")),
this::opBlocksInjections
)
fun register(consumer: (holder: ItemGroupHolder) -> CreativeModeTab) {
ALL.forEach(consumer::invoke)
@@ -96,13 +165,20 @@ object CobblemonItemGroups {
val displayName: Component = Component.translatable("itemGroup.${key.location().namespace}.${key.location().path}")
)
private fun create(name: String, entryCollector: DisplayItemsGenerator, displayIconProvider: () -> ItemStack): ResourceKey<CreativeModeTab> {
private fun create(
name: String,
entryCollector: DisplayItemsGenerator,
displayIconProvider: () -> ItemStack
): ResourceKey<CreativeModeTab> {
val key = ResourceKey.create(BuiltInRegistries.CREATIVE_MODE_TAB.key(), cobblemonResource(name))
this.ALL += ItemGroupHolder(key, displayIconProvider, entryCollector)
return key
}
private fun inject(key: ResourceKey<CreativeModeTab>, consumer: (injector: Injector) -> Unit): (injector: Injector) -> Unit {
private fun inject(
key: ResourceKey<CreativeModeTab>,
consumer: (injector: Injector) -> Unit
): (injector: Injector) -> Unit {
this.INJECTORS[key] = consumer
return consumer
}
@@ -122,6 +198,14 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.GALARICA_NUTS)
entries.accept(CobblemonItems.HEARTY_GRAINS)
entries.accept(CobblemonItems.TASTY_TAIL)
entries.accept(CobblemonItems.POMOHANA)
entries.accept(CobblemonItems.PAUVILLEA)
entries.accept(CobblemonItems.LOBAILA)
entries.accept(CobblemonItems.WISTENSU)
entries.accept(CobblemonItems.VOLTACONIA)
entries.accept(CobblemonItems.VERDROOT)
entries.accept(CobblemonItems.MISTLEAF)
entries.accept(CobblemonItems.LUCIBELL)
// entries.accept(CobblemonItems.BUGWORT) // TODO after 1.7
entries.accept(CobblemonItems.RED_APRICORN)
@@ -295,8 +379,7 @@ object CobblemonItemGroups {
DataComponents.BLOCK_STATE,
BlockItemStateProperties.EMPTY
.with(TypeGemClusterBlock.STAGE, i)
.with(TypeGemClusterBlock.SHOULD_GROW, false)
.with(TypeGemClusterBlock.STUNTED, false)
.with(TypeGemClusterBlock.GROWTH_TYPE, TypeGemClusterBlock.GrowthType.DECORATION)
)
stack.set(
DataComponents.CUSTOM_MODEL_DATA,
@@ -631,8 +714,6 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.ABILITY_CAPSULE)
entries.accept(CobblemonItems.ABILITY_PATCH)
entries.accept(CobblemonItems.BLANK_TM)
entries.accept(CobblemonItems.POKE_BAIT)
entries.accept(CobblemonItems.POKE_SNACK)
entries.accept(CobblemonItems.POKE_CAKE)
@@ -649,15 +730,17 @@ object CobblemonItemGroups {
private fun defaultAprijuice(item: AprijuiceItem): ItemStack {
return ItemStack(item).apply {
this.set(CobblemonItemComponents.RIDE_BOOST, RideBoostsComponent(
mapOf(
RidingStat.ACCELERATION to 1,
RidingStat.JUMP to 1,
RidingStat.SPEED to 1,
RidingStat.STAMINA to 1,
RidingStat.SKILL to 1
this.set(
CobblemonItemComponents.RIDE_BOOST, RideBoostsComponent(
mapOf(
RidingStat.ACCELERATION to 1,
RidingStat.JUMP to 1,
RidingStat.SPEED to 1,
RidingStat.STAMINA to 1,
RidingStat.SKILL to 1
)
)
))
)
}
}
@@ -848,6 +931,16 @@ object CobblemonItemGroups {
entries.accept(CobblemonItems.PSYCHIC_SEED)
}
private fun tmItemEntries(displayContext: ItemDisplayParameters, entries: Output) {
entries.accept(CobblemonItems.BLANK_TM)
TechnicalMachines
.tmMap
.entries
.sortedBy { it.value.moveName.name }
.sortedBy { it.value.moveName.elementalType.order }
.forEach { entries.accept(TMMoveComponent.createStack(it.value.moveName)) }
}
private fun utilityItemEntries(displayContext: ItemDisplayParameters, entries: Output) {
CobblemonItems.pokeBalls.forEach(entries::accept)
CobblemonItems.pokeRods.forEach(entries::accept)
@@ -855,7 +948,7 @@ object CobblemonItemGroups {
}
private fun blocksInjections(injector: Injector) {
if(Cobblemon.implementation.isModInstalled("adorn")) { //adorn modifies vanilla block tab and if we don't follow suit we crash the game
if (Cobblemon.implementation.isModInstalled("adorn")) { //adorn modifies vanilla block tab and if we don't follow suit we crash the game
injector.putLast(CobblemonItems.APRICORN_LOG)
injector.putLast(CobblemonItems.APRICORN_WOOD)
injector.putLast(CobblemonItems.STRIPPED_APRICORN_LOG)
@@ -974,7 +1067,10 @@ object CobblemonItemGroups {
injector.putAfter(CobblemonItems.NOSTALGIC_SHERD, CobblemonItems.HELIX_SHERD)
injector.putAfter(CobblemonItems.SUSPICIOUS_SHERD, CobblemonItems.NOSTALGIC_SHERD)
injector.putAfter(CobblemonItems.AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE, Items.SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE)
injector.putAfter(
CobblemonItems.AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE
)
injector.putAfter(CobblemonItems.POKEROD_SMITHING_TEMPLATE, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE)
}
@@ -43,6 +43,8 @@ object TMMachineTeachMoveHandler : ServerNetworkPacketHandler<TMMachineTeachMove
!pokemon.moveSet.getMoveTemplates().contains(moveTemplate) &&
!pokemon.allAccessibleMoves.contains(moveTemplate)
) {
menu.incrementStateId()
if (!player.isCreative && !Cobblemon.config.infiniteTmUses) menu.carried.shrink(1)
if (pokemon.moveSet.hasSpace()) {
@@ -58,4 +60,4 @@ object TMMachineTeachMoveHandler : ServerNetworkPacketHandler<TMMachineTeachMove
player.playNotifySound(CobblemonSounds.MOVE_LEARN, SoundSource.MASTER, 1.0F, 1.0F)
}
}
}
}
@@ -105,6 +105,7 @@ import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.requirements.BlocksTraveledRequirement
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.pokemon.status.PersistentStatusContainer
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.codec.internal.ClientPokemonP1
import com.cobblemon.mod.common.util.codec.internal.ClientPokemonP2
@@ -211,8 +212,9 @@ open class Pokemon : ShowdownIdentifiable {
// Species updates already update HP but just a form change may require it
// Moved to before the field was set else it won't actually do the hp calc proper <3
val quotient = clamp(currentHealth / maxHealth.toFloat(), 0F, 1F)
val oldForm = field
field = value
this.updateMovesOnFormChange(value)
this.updateMovesOnFormChange(oldForm)
// Evo proxy is already cleared on species update but the form may be changed by itself, this is fine and no unnecessary packets will be sent out
this.evolutionProxy.current().clear()
checkGender()
@@ -469,7 +471,7 @@ open class Pokemon : ShowdownIdentifiable {
*/
var gmaxFactor = false
set(value) {
val evolutions = species.standardForm.evolutions.mapNotNull { it.result.species }.mapNotNull { PokemonSpecies.getByName(it) }
val evolutions = species.standardForm.evolutions.mapNotNull { it.result.species }.mapNotNull { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }
if (species.canGmax() || evolutions.find { it.canGmax() } != null) {
field = value
onChange(GmaxFactorUpdatePacket({ this }, value))
@@ -2301,15 +2303,16 @@ open class Pokemon : ShowdownIdentifiable {
*
* E.g, Removing Overheat from Rotom when it is no longer Rotom-Heat and the target form is not compatible with Overheat.
*/
private fun updateMovesOnFormChange(newForm: FormData) {
private fun updateMovesOnFormChange(oldForm: FormData) {
if (this.isClient) return
val oldFormChangeMoves = this.form.moves.formChangeMoves.toSet()
val newForm = this.form
val oldFormChangeMoves = oldForm.moves.formChangeMoves.toSet()
// Only remove moves that were provided by the old form's form-change moves AND are not learnable by the new form
for (i in 0 until MoveSet.MOVE_COUNT) {
val move = this.moveSet[i]
if (move != null && move.template in oldFormChangeMoves) {
if (move != null && move.template in oldFormChangeMoves && !LearnsetQuery.ANY.canLearn(move.template, newForm.moves)) {
this.moveSet.setMove(i, null)
}
}
@@ -2322,16 +2325,8 @@ open class Pokemon : ShowdownIdentifiable {
}
}
// Add new form's form-change moves
newForm.moves.formChangeMoves.forEach { move ->
if (this.moveSet.filterNotNull().none { it.template == move }) {
if (this.moveSet.hasSpace()) {
this.moveSet.add(move.create())
} else {
this.benchedMoves.add(BenchedMove(move, 0))
}
}
}
// Add the new form's form-change moves (skipping any the Pokémon isn't high enough level for yet).
grantEligibleFormChangeMoves()
// If moveset is empty try to find one valid move to fill it
if (this.moveSet.filterNotNull().isEmpty()) {
@@ -2343,6 +2338,30 @@ open class Pokemon : ShowdownIdentifiable {
}
}
/**
* Grants any of the current form's `form_change` moves that this Pokémon doesn't already know and is high
* enough level for (form-change moves that are also level-up moves, e.g. Glaciate on Kyurem, shouldn't be
* granted until that level is reached).
*/
private fun grantEligibleFormChangeMoves() {
if (this.isClient) return
this.form.moves.formChangeMoves.forEach { move ->
if (this.moveSet.filterNotNull().none { it.template == move } && this.benchedMoves.none { it.moveTemplate == move }) {
val requiredLevel = this.form.moves.levelUpMoves.entries.firstOrNull { move in it.value }?.key
if (requiredLevel != null && this.level < requiredLevel) {
return@forEach
}
if (this.moveSet.hasSpace()) {
this.moveSet.add(move.create())
} else {
this.benchedMoves.add(BenchedMove(move, 0))
}
}
}
}
companion object {
/**
* The [FriendshipMutationCalculator] used when a Pokémon levels up.
@@ -173,6 +173,7 @@ class Species : ShowdownIdentifiable {
.addStandardFunctions()
.addSpeciesFunctions(this)
var silenceStepSounds = false
fun initialize() {
Cobblemon.statProvider.provide(this)
@@ -265,6 +266,7 @@ class Species : ShowdownIdentifiable {
}
this.riding.encode(buffer)
buffer.writeBoolean(this.silenceStepSounds)
}
fun decode(buffer: RegistryFriendlyByteBuf) {
@@ -308,6 +310,7 @@ class Species : ShowdownIdentifiable {
}
}
this.riding = RidingProperties.decode(buffer)
this.silenceStepSounds = buffer.readBoolean()
this.initialize()
}
@@ -234,11 +234,11 @@ fun Entity.isDusk(): Boolean {
}
fun Entity.isStandingOn(blocks: Set<String>, depth: Int = 2): Boolean {
for (currentDepth in 1..depth) {
val bellowBlockPos = blockPosition().below(currentDepth)
for (currentDepth in 0..depth) {
val bellowBlockPos = blockPosBelowThatAffectsMyMovement.below(currentDepth)
val blockState = level().getBlockState(bellowBlockPos)
if (blockState.isAir || !blockState.isCollisionShapeFullBlock(level(), bellowBlockPos)) continue
if (blockState.isAir) continue
val elementOrTags = ExtraCodecs.TAG_OR_ELEMENT_ID.listOf().decode(JavaOps.INSTANCE, blocks.toList()).result().get().first
elementOrTags.forEach {
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.world.feature
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonBlocks.TYPE_GEM_CORE
import com.cobblemon.mod.common.CobblemonBlocks.typeGemBlocks
import com.cobblemon.mod.common.block.TypeGemCoreBlock
@@ -51,7 +52,9 @@ class TypeGemFeature : Feature<BlockStateConfiguration>(BlockStateConfiguration.
// Trigger forced growth with clusters
val coreBlock = coreState.block as TypeGemCoreBlock
coreBlock.forceGrow(worldGenLevel, origin, random, 0.5f)
repeat(Cobblemon.config.typeGemInitialExpansionCycles) {
coreBlock.expand(worldGenLevel, origin, random, true)
}
// println("[TypeGemFeature] Placed ${gemId.path} at $chosenPos")
return true
@@ -0,0 +1,75 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:greninja_cloud",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particle/vanilla/big_smoke_white"
}
},
"events": {
"cloudfade": {
"particle_effect": {
"effect": "cobblemon:greninja_cloud_fade",
"type": "particle_with_velocity"
}
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": "math.random_integer(10,12)"
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_box": {
"offset": [0, 1, 0],
"half_dimensions": [0.35, 0.75, 0.35],
"direction": ["math.round(math.random(-1,1))", 0, "math.round(math.random(-1,1))"]
},
"minecraft:particle_initialization": {
"per_render_expression": "v.smoke_color = v.particle_random_3;v.smoke_rotation = math.round(v.particle_random_2)*90;"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "0.7+(0.1*math.round(v.particle_random_4))"
},
"minecraft:particle_lifetime_events": {
"expiration_event": "cloudfade"
},
"minecraft:particle_initial_spin": {
"rotation": "v.smoke_rotation"
},
"minecraft:particle_initial_speed": 0.85,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, "0.75+(0.75*math.round(v.particle_random_4))", 0],
"linear_drag_coefficient": 2
},
"minecraft:particle_appearance_billboard": {
"size": [0.4, 0.4],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
"texture_height": 192,
"flipbook": {
"base_UV": [0, 160],
"size_UV": [16, 16],
"step_UV": [0, -16],
"frames_per_second": 28,
"max_frame": 7
}
}
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.smoke_color",
"gradient": {
"0.0": "#FFE8E8E8",
"1.0": "#FFC1C1C1"
}
}
}
}
}
}
@@ -0,0 +1,57 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:greninja_cloud_fade",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particle/vanilla/big_smoke_white"
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.2
},
"minecraft:particle_initial_spin": {
"rotation": "v.smoke_rotation"
},
"minecraft:particle_initial_speed": 0.85,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, 1.5, 0],
"linear_drag_coefficient": 2
},
"minecraft:particle_appearance_billboard": {
"size": [0.3, 0.3],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
"texture_height": 192,
"flipbook": {
"base_UV": [0, 80],
"size_UV": [16, 16],
"step_UV": [0, 16],
"frames_per_second": 32,
"max_frame": 7
}
}
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.smoke_color",
"gradient": {
"0.0": "#FFE8E8E8",
"1.0": "#FFC1C1C1"
}
}
}
}
}
}
@@ -0,0 +1,82 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:greninja_smoke",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particle/vanilla/generic"
}
},
"curves": {
"variable.smokesize": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0.37, 0.85, 1, 1, 1, 0.88, 0.55, 0]
}
},
"events": {
"cloud": {
"particle_effect": {
"effect": "cobblemon:greninja_cloud",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 150,
"max_particles": 200
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.15
},
"minecraft:emitter_lifetime_events": {
"creation_event": "cloud"
},
"minecraft:emitter_shape_disc": {
"offset": [0, "v.particle_random_4*0.75", 0],
"radius": 0.35,
"direction": "outwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "math.random(0.55,0.65)"
},
"minecraft:particle_initial_spin": {
"rotation": "math.round(v.particle_random_4*3)*90"
},
"minecraft:particle_initial_speed": 2,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, "math.random(0.75,1)", 0],
"linear_drag_coefficient": 0.85
},
"minecraft:particle_appearance_billboard": {
"size": ["(0.13*v.smokesize)-(v.particle_random_3*0.07)", "(0.13*v.smokesize)-(v.particle_random_3*0.07)"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 64,
"texture_height": 8,
"flipbook": {
"base_UV": [56, 0],
"size_UV": [8, 8],
"step_UV": [-8, 0],
"frames_per_second": 10,
"max_frame": 8
}
}
},
"minecraft:particle_appearance_lighting": {},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_random_3",
"gradient": {
"0.0": "#FFBDBDBD",
"0.5": "#FF8F8F8F",
"1.0": "#FF666666"
}
}
}
}
}
}
@@ -1815,6 +1815,12 @@
"wings_open": {
"scale": 0
}
},
"timeline": {
"0.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
"0.5": "q.run_molang('cobblemon:stepsound_claw_medium');",
"1.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
"1.5": "q.run_molang('cobblemon:stepsound_claw_medium');"
}
},
"animation.pidgeot.mount_ground_idle": {
@@ -3631,6 +3637,12 @@
"wings_open": {
"scale": 0
}
},
"timeline": {
"0.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
"0.5": "q.run_molang('cobblemon:stepsound_claw_medium');",
"1.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
"1.5": "q.run_molang('cobblemon:stepsound_claw_medium');"
}
},
"animation.pidgeot.ride_ground_walk": {
@@ -1682,6 +1682,12 @@
"1.3333": [10, 9, 0]
}
}
},
"timeline": {
"0.0": "q.run_molang('cobblemon:stepsound_standard_medium');",
"0.4583": "q.run_molang('cobblemon:stepsound_standard_medium');",
"0.6667": "q.run_molang('cobblemon:stepsound_standard_medium');",
"1.125": "q.run_molang('cobblemon:stepsound_standard_medium');"
}
},
"animation.arcanine.ride_ground_walk": {
@@ -2639,6 +2645,12 @@
"chest_fluff_right": {
"rotation": [5, "-22.5+math.cos(q.anim_time*90*8-120)*15", "-math.sin(q.anim_time*90*8-120)*3"]
}
},
"timeline": {
"0.125": "q.run_molang('cobblemon:stepsound_standard_medium');",
"0.2083": "q.run_molang('cobblemon:stepsound_standard_large');",
"0.2917": "q.run_molang('cobblemon:stepsound_standard_medium');",
"0.375": "q.run_molang('cobblemon:stepsound_standard_medium');"
}
},
"animation.arcanine.ride_ground_run": {
@@ -4161,41 +4173,101 @@
"eye_left": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
"0.5": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
"1.6667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0, 0, 0],
"post": [-0.1, 0, 0.1]
},
"0.5": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0, 0.1]
},
"1.6667": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
"0.5": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
"1.6667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0, 0, 0],
"post": [0.1, 0, 0.1]
},
"0.5": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0, 0.1]
},
"1.6667": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.5": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"1.6667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.5": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"1.6667": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.5": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"1.6667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.5": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"1.6667": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"jaw": {
@@ -4823,41 +4895,101 @@
"eye_left": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
"0.5": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
"1.6667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0, 0, 0],
"post": [-0.1, 0, 0.1]
},
"0.5": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0, 0.1]
},
"1.6667": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
"0.5": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
"1.6667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0, 0, 0],
"post": [0.1, 0, 0.1]
},
"0.5": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0, 0.1]
},
"1.6667": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.5": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"1.6667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.5": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"1.6667": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.5": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"1.6667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.1667": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.5": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"1.6667": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"jaw": {
@@ -5287,14 +5419,20 @@
"position": {
"0.0": [-0.1, 0, 0.1],
"0.125": [-0.1, 0, 0.1],
"0.1667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]}
"0.1667": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
}
}
},
"eye_right": {
"position": {
"0.0": [0.1, 0, 0.1],
"0.125": [0.1, 0, 0.1],
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
"0.1667": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
}
}
}
}
@@ -5491,47 +5629,95 @@
"eye_left": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.2, 0, 0.1]
},
"0.3333": {
"pre": [-0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [0.2, 0, 0.1]
},
"0.3333": {
"pre": [0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.2, 0, 0.1]
},
"0.3333": {
"pre": [-0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [0.2, 0, 0.1]
},
"0.3333": {
"pre": [0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left_hurt": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.3333": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.3333": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
}
}
},
"eyelid_right_hurt": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.3333": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
}
}
},
"jaw": {
@@ -6238,47 +6424,95 @@
"eye_left": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.2, 0, 0.1]
},
"0.3333": {
"pre": [-0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [0.2, 0, 0.1]
},
"0.3333": {
"pre": [0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.2, 0, 0.1]
},
"0.3333": {
"pre": [-0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [0.2, 0, 0.1]
},
"0.3333": {
"pre": [0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
}
},
"eyelid_left_hurt": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.3333": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.3333": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
}
}
},
"eyelid_right_hurt": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.3333": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
}
}
},
"jaw": {
@@ -1,67 +1,6 @@
{
"format_version": "1.8.0",
"animations": {
"animation.shinx.new": {
"loop": true,
"bones": {
"waist": {
"rotation": [-32.5, 0, 0]
},
"tail_1": {
"rotation": [-9.00717, 20.70481, 65.85133]
},
"tail_2": {
"rotation": [67.5, 0, 0]
},
"tail_3": {
"rotation": [45, 45, 0]
},
"head": {
"rotation": [-4.11405, -22.13991, 10.80524]
},
"eye_left": {
"position": [0, 0, 1]
},
"eyelid_right2": {
"position": [0, 0, -3]
},
"ear_left": {
"rotation": [0, 0, 12.5]
},
"ear_right": {
"rotation": [0, 0, -12.5]
},
"fluff": {
"rotation": [0, 0, 20]
},
"open_mouth": {
"position": [0, 0, -2]
},
"closed_mouth": {
"position": [0, 0, 1]
},
"back_leg_right": {
"rotation": [-40.08019, 31.37238, 1.3824],
"position": [0, -1.5, -1]
},
"knee_right": {
"rotation": [45, 0, 0]
},
"front_foot_right": {
"rotation": [0, -5, 0]
},
"back_leg_left": {
"rotation": [-40.08019, -31.37238, -1.3824],
"position": [0, -1.5, -1]
},
"knee_left": {
"rotation": [45, 0, 0]
},
"front_foot_left": {
"rotation": [0, 5, 0]
}
}
},
"animation.shinx.ground_idle": {
"loop": true,
"bones": {
@@ -75,6 +14,71 @@
"tail_3": {
"rotation": [-37.5, 0, 0],
"position": [0, 0.1, -0.3]
},
"leg_front_right": {
"rotation": [0, 2.5, 0]
},
"leg_front_left": {
"rotation": [0, -2.5, 0]
},
"leg_back_right": {
"rotation": [0, 7.5, 2.5]
},
"leg_back_left": {
"rotation": [0, -7.5, 0]
}
}
},
"animation.shinx.blink": {
"animation_length": 0.1667,
"bones": {
"eye_right": {
"position": {
"0.0": [0.1, 0, 0.1],
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_left": {
"position": {
"0.0": [-0.1, 0, 0.1],
"0.1667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [-0.1, 0, -0.1],
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0.1, 0, -0.1],
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.shinx.ditto_face": {
"loop": true,
"bones": {
"face": {
"position": [0, 0, 0.1],
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
}
@@ -1,133 +1,94 @@
{
"format_version": "1.8.0",
"animations": {
"animation.luxio.idle": {
"animation.luxio.ground_idle": {
"loop": true,
"bones": {
"ear_right": {
"rotation": [0, 0, -22.5]
},
"ear_left": {
"rotation": [0, 0, 22.5]
},
"cheek_fluff_left": {
"rotation": [0, 0, 22.5]
},
"cheek_fluff_right": {
"rotation": [0, 0, -22.5]
},
"tail": {
"rotation": [37.5, 0, 0]
"rotation": [35, 0, 0]
},
"tail_2": {
"rotation": [-17.5, 0, 0]
"tail2": {
"rotation": [-30, 0, 0]
},
"tail_3": {
"rotation": [-32.5, 0, 0]
"tail3": {
"rotation": [-30, 0, 0]
},
"tail_4": {
"rotation": [-32.5, 0, 0]
"tail4": {
"rotation": [-25, 0, 0]
},
"tail_fluff_top": {
"rotation": [5, 0, 0]
},
"leg_back_right": {
"rotation": [0, 7.5, 5]
},
"foot_back_right2": {
"rotation": [0, 0, -5]
},
"leg_back_left": {
"rotation": [0, -7.5, -5]
},
"foot_back_left2": {
"rotation": [0, 0, 5]
},
"leg_front_right": {
"rotation": [0, 5, 0]
},
"leg_front_left": {
"rotation": [0, -5, 0]
}
}
},
"animation.luxio.sleep": {
"loop": true,
"animation.luxio.blink": {
"animation_length": 0.1667,
"bones": {
"body": {
"position": [0, -4, 0]
"eye_right": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"back_leg_right": {
"rotation": [-90, 45, 0],
"position": [4, 1, 1]
},
"knee_right": {
"rotation": [90, 0, 0],
"position": [0, 1, 1]
},
"back_paw_right": {
"position": [0, 1, 0]
},
"back_leg_left": {
"rotation": [-90, 45, 0],
"position": [4, 1, -3]
},
"knee_left": {
"rotation": [90, 0, 0],
"position": [0, 1, 1]
},
"back_paw_left": {
"position": [0, 1, 0]
},
"front_leg_right": {
"rotation": [-45, 0, 0]
},
"elbow_right": {
"rotation": [-42.73421, -15.69986, -16.32495]
},
"front_paw_right": {
"rotation": [90, 0, 0]
},
"front_leg_left": {
"rotation": [-47.41981, -31.37238, 1.3824]
},
"elbow_left": {
"rotation": [-42.73421, 15.69986, 16.32495]
},
"front_paw_left": {
"rotation": [90, 0, 0]
},
"head": {
"rotation": [-7.5, -22.5, 0],
"position": [0, -1.25, -1.25]
},
"waist": {
"rotation": [0, 45, 0]
},
"tail": {
"rotation": [-22.5, 22.5, 0],
"position": [0, -0.75, 0]
},
"tail_2": {
"rotation": [0, 67.5, 0]
},
"tail_3": {
"rotation": [7.86119, 40.78947, 20.94102]
},
"tail_4": {
"rotation": [0, 22.5, 0]
},
"tail_5": {
"rotation": [22.5, 0, 0]
},
"neck": {
"rotation": [22.5, 0, 0]
},
"ear_right": {
"rotation": [0, 0, -22.5]
},
"ear_left": {
"rotation": [0, 0, 22.5]
},
"head_fluff_top": {
"rotation": [0, 0, -45]
},
"eyelid_l": {
"position": [0, 0, -3]
},
"eyelid_r": {
"position": [0, 0, -2]
},
"cheek_fluff_left": {
"rotation": [0, 22.5, 22.5]
},
"cheek_fluff_right": {
"rotation": [22.5, 0, -22.5]
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"eye_left": {
"position": [0, 0, 1]
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": [0, 0, 1]
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.luxio.ditto_face": {
"loop": true,
"bones": {
"face": {
"position": [0, 0, 0.1],
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
}
@@ -1,161 +1,103 @@
{
"format_version": "1.8.0",
"animations": {
"animation.luxray.new": {
"loop": true,
"bones": {
"body": {
"rotation": [22.5, 0, 0],
"position": [0, -2, 0]
},
"torso": {
"rotation": [-22.5, 0, 0]
},
"waist": {
"rotation": [24.14867, -20.70481, -9.00717]
},
"hips": {
"rotation": [-22.81179, 9.23186, -3.86032]
},
"tail_1": {
"rotation": [49.98844, 27.36694, 17.18133]
},
"tail_2": {
"rotation": [-22.5, 22.5, 0]
},
"tail_3": {
"rotation": [-53.52293, 35.66466, -17.31806]
},
"tail_4": {
"rotation": [45, 45, 0]
},
"tail_5": {
"rotation": [45, 45, 0]
},
"tail_6": {
"rotation": [0, 22.5, 0]
},
"neck": {
"rotation": [62.26579, -15.69986, -16.32495],
"position": [0, -1, 0]
},
"head": {
"rotation": [-48.75474, -3.08149, 16.32258],
"position": [0, -0.75, 0]
},
"mouth": {
"rotation": [55, 0, 0]
},
"head_fluff_center_2": {
"rotation": [0, 0, 22.5]
},
"head_fluff_center_3": {
"rotation": [0, 22.5, 0]
},
"head_fluff_top_right": {
"rotation": [0, 22.5, 0]
},
"head_fluff_top_2_right": {
"rotation": [0, 22.5, 0]
},
"head_fluff_top_left": {
"rotation": [0, 0, 0]
},
"head_fluff_top_2_left": {
"rotation": [0, 22.5, 0]
},
"head_fluff_bottom_right": {
"rotation": [0, 22.5, 0]
},
"head_fluff_bottom_left": {
"rotation": [0, 22.5, 0]
},
"head_fluff_bottom_2_left": {
"rotation": [0, 22.5, 0]
},
"ear_right": {
"rotation": [0, 0, -17.5]
},
"ear_left": {
"rotation": [0, 0, 17.5]
},
"front_leg_right": {
"rotation": [-44.56145, 7.05302, 7.10708],
"position": [0, -0.31732, -0.92388]
},
"elbow_right": {
"rotation": [-42.73421, -15.69986, -16.32495]
},
"front_foot_right": {
"rotation": [67.5, 0, 0]
},
"front_leg_left": {
"rotation": [22.5, 0, 0],
"position": [1.25, 1, 0]
},
"elbow_left": {
"rotation": [-47.26579, -15.69986, 16.32495],
"position": [-0.5, 0, 0]
},
"front_foot_left": {
"rotation": [0, 10, 0]
},
"back_leg_right": {
"rotation": [-46.64867, -20.70481, 9.00717],
"position": [-5, -2.38896, -2.07193]
},
"knee_right": {
"rotation": [67.5, 0, 0],
"position": [0.76537, 0.33755, 1.86018]
},
"leg_right": {
"rotation": [10, 0, 0]
},
"back_foot_right": {
"rotation": [-57.5, 0, 0]
},
"back_leg_left": {
"rotation": [-19.83264, -18.43795, -6.24926]
},
"knee_left": {
"rotation": [0, 0, 12.5]
},
"leg_left": {
"rotation": [7.5, 0, 0]
},
"back_foot_left": {
"rotation": [-7.5, 0, 0]
}
}
},
"animation.luxray.ground_idle": {
"loop": true,
"bones": {
"tail_1": {
"rotation": [43, 0, 0]
"tail": {
"rotation": [30, 0, 0]
},
"tail_2": {
"rotation": [22.5, 0, 0],
"position": [0, 0, -0.2]
"tail2": {
"rotation": [25, 0, 0]
},
"tail_3": {
"rotation": [-45, 0, 0],
"position": [0, 0.1, -0.3]
"tail3": {
"rotation": [-45, 0, 0]
},
"tail_4": {
"rotation": [-52.68932, -2.64422, -1.88999],
"position": [0, 0.2, -0.4]
"tail4": {
"rotation": [-45, 0, 0]
},
"tail_5": {
"rotation": [-30, 0, 0],
"position": [0, 0.1, -0.2]
"tail5": {
"rotation": [-35, 0, 0]
},
"tail_6": {
"rotation": [20, 0, 0],
"position": [0, 0, -0.1]
},
"tail_fluff": {
"tail_fluff_top": {
"rotation": [5, 0, 0]
},
"tail6": {
"rotation": [35, 0, 0]
},
"tail7": {
"rotation": [20, 0, 0]
},
"leg_front_left": {
"rotation": [0, 0, 0]
},
"leg_front_right": {
"rotation": [0, 5, 0]
},
"leg_back_left": {
"rotation": [0, -7.5, -2.5]
},
"foot_back_left2": {
"rotation": [0, 0, 2.5]
},
"leg_back_right": {
"rotation": [0, 7.5, 2.5]
},
"foot_back_right2": {
"rotation": [0, 0, -2.5]
}
}
},
"animation.luxray.blink": {
"animation_length": 0.1667,
"bones": {
"eye_left": {
"position": {
"0.0": [-0.1, 0, 0.1],
"0.1667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0.1, 0, 0.1],
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0.1, 0, -0.1],
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [-0.1, 0, -0.1],
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.luxray.ditto_face": {
"loop": true,
"bones": {
"face": {
"position": [0, 0, 0.1],
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
}
@@ -1,6 +1,179 @@
{
"format_version": "1.8.0",
"animations": {
"animation.chespin.blink": {
"animation_length": 0.1667,
"bones": {
"eye_left": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.chespin.cry": {
"animation_length": 1,
"bones": {
"head": {
"rotation": {
"0.0": [0, 0, 0],
"0.125": {
"pre": [-12, 0, 0],
"post": [-12, 0, 0],
"lerp_mode": "catmullrom"
},
"0.2917": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.5833": {
"post": [-12, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0": [0, 0, 0]
}
},
"mouth_closed_smile": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"0.75": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_smile": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.75": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"mouth_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"0.75": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.75": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
},
"sound_effects": {
"0.1667": {
"effect": "pokemon.chespin.cry"
}
}
},
"animation.chespin.ditto_face": {
"loop": true,
"bones": {
"face": {
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
},
"animation.chespin.pose": {
"loop": true,
"bones": {
"body": {
"rotation": [0, -37.5, 0],
"position": [0, 0.5, 0]
},
"torso": {
"rotation": [15, 0, 0]
},
"torso2": {
"rotation": [-12.5, 0, 0]
},
"head": {
"rotation": [-13.89157, 20.57373, -10.30286]
},
"arm_right": {
"rotation": [4.68184, 16.2524, -29.6444]
},
"hand_right": {
"rotation": [0, 0, 15]
},
"arm_left": {
"rotation": [34.92019, 17.2337, 20.34505]
},
"hand_left": {
"rotation": [0, 0, -17.5]
},
"tail": {
"rotation": [-51.63554, -16.76559, 11.06517],
"position": [-1, 0, 0]
},
"tail2": {
"rotation": [0, -37.5, 0]
},
"leg_right": {
"rotation": [0, 22.5, 0]
},
"foot_right": {
"rotation": [22.5, 0, 0]
},
"toes_right": {
"rotation": [-22.5, 0, 0]
},
"leg_left": {
"rotation": [7.53535, -3.55508, -21.73761]
},
"foot_left": {
"rotation": [17.45752, -7.82184, 22.22986]
},
"toes_left": {
"rotation": [-22.5, 0, 0]
},
"head_spikes_sharp": {
"scale": 0
},
"pupil_left": {
"position": [0, 0.2, 0]
},
"pupil_right": {
"position": [-0.2, 0.2, 0]
}
}
},
"animation.chespin.ground_idle": {
"loop": true,
"bones": {
@@ -52,6 +225,9 @@
},
"head": {
"rotation": ["math.sin(q.anim_time*90*3-60)*1.5", "-math.sin(q.anim_time*90*1.5-90)*6.5", 0]
},
"head_spikes_sharp": {
"scale": 0
}
}
},
@@ -106,6 +282,9 @@
},
"toe_right": {
"rotation": ["math.clamp(math.sin(q.anim_time*90*5+40)*40,-180,0)", 0, 0]
},
"head_spikes_sharp": {
"scale": 0
}
}
},
@@ -134,14 +313,14 @@
"mouth_open": {
"position": [0, 0, -0.1]
},
"spike_head_left": {
"head_spike_left": {
"rotation": ["-5+math.sin(q.anim_time*90*1-90)*5", 0, -22.5]
},
"spike_head_right": {
"head_spike_right": {
"rotation": ["-5+math.sin(q.anim_time*90*1-90)*5", 0, 45],
"position": [0, 0.5, 0]
},
"spikes_back": {
"head_spikes_back": {
"rotation": ["math.sin(q.anim_time*90*1-135)*5", 0, 0]
},
"arm_left": {
@@ -173,79 +352,21 @@
},
"foot_right": {
"rotation": [35.02686, -1.60667, -1.91561]
}
}
},
"animation.chespin.blink": {
"animation_length": 0.16667,
"bones": {
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
}
}
}
},
"animation.chespin.cry": {
"animation_length": 0.91667,
"bones": {
"head": {
"rotation": {
"0.0": ["-5+math.sin(q.anim_time*90*6+45)*8", 0, 0],
"0.1667": ["-5+math.sin(q.anim_time*90*6+45)*8", 0, 0],
"0.8333": [0, 0, 0]
}
},
"mouth_open3": {
"eye_left": {
"position": [0, 0, 0.1]
},
"mouth_closed": {
"position": {
"0.0833": [0, 0, 0],
"0.1667": [0, 0, 0.1],
"0.4167": [0, 0, 0.1],
"0.5": [0, 0, 0]
}
"eye_right": {
"position": [0, 0, 0.2]
},
"mouth_open": {
"position": {
"0.0833": [0, 0, 0],
"0.1667": [0, 0, -0.1],
"0.4167": [0, 0, -0.1],
"0.5": [0, 0, 0]
}
"mouth_closed_smile": {
"position": [0, 0, 0.2]
},
"spike_head_left": {
"rotation": {
"0.0": [0, 0, "-10+math.sin(q.anim_time*90*6+45)*8"],
"0.1667": [0, 0, "-10+math.sin(q.anim_time*90*6+45)*8"],
"0.3333": [0, 0, "-20+math.sin(q.anim_time*90*3+95)*8"],
"0.5833": [0, 0, "-20+math.sin(q.anim_time*90*3+95)*8"],
"0.8333": [0, 0, 0]
}
"mouth_closed_neutral": {
"position": [0, 0, -0.2]
},
"spike_head_right": {
"rotation": {
"0.0": [0, 0, "10-math.sin(q.anim_time*90*6+45)*8"],
"0.1667": [0, 0, "10-math.sin(q.anim_time*90*6+45)*8"],
"0.3333": [0, 0, "20-math.sin(q.anim_time*90*3+95)*8"],
"0.5833": [0, 0, "20-math.sin(q.anim_time*90*3+95)*8"],
"0.9167": [0, 0, 0]
}
}
},
"sound_effects": {
"0.0833": {
"effect": "pokemon.chespin.cry"
"head_spikes_sharp": {
"scale": 0
}
}
}
@@ -1,6 +1,205 @@
{
"format_version": "1.8.0",
"animations": {
"animation.quilladin.blink": {
"animation_length": 0.1667,
"bones": {
"eye_left": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.quilladin.cry": {
"animation_length": 1.5,
"bones": {
"torso2": {
"rotation": {
"0.0": [0, 0, 0],
"0.0833": {
"pre": [2, 0, 0],
"post": [2, 0, 0],
"lerp_mode": "catmullrom"
},
"0.2917": {
"post": [-2.5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.5833": {
"post": [-2.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [1, 0, 0],
"lerp_mode": "catmullrom"
},
"1.4167": [0, 0, 0]
}
},
"mouth_closed_smile": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.3333": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_smile": {
"position": {
"0.0": [0, 0, 0],
"0.375": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.0417": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"mouth_open_o": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.375": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"1.0417": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.3333": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
},
"mouth_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"1.3333": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"1.3333": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
},
"sound_effects": {
"0.1667": {
"effect": "pokemon.quilladin.cry"
}
}
},
"animation.quilladin.ditto_face": {
"loop": true,
"bones": {
"face": {
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
},
"animation.quilladin.pose": {
"loop": true,
"bones": {
"body": {
"position": [0, 2, 0]
},
"torso": {
"rotation": [-27.43745, 1.50179, 4.76968]
},
"tail": {
"rotation": [-15.02687, 1.91486, -1.60757],
"position": [0, -1, 0]
},
"tail2": {
"rotation": [7.56397, 7.43547, 0.98448]
},
"tail3": {
"rotation": [10.08453, 7.38542, 1.30962]
},
"torso2": {
"rotation": [7.49294, -0.32621, -2.52136]
},
"pupil_left": {
"position": [0.1, 0.1, 0]
},
"mouth_closed_smile": {
"position": [0, 0, 0.1]
},
"mouth_open_smile": {
"position": [0, 0, -0.1]
},
"hair": {
"rotation": [-27.5, 0, 0]
},
"arm_left": {
"rotation": [-73.6118, 1.34454, -14.51378]
},
"finger_front_left": {
"rotation": [0, 12.5, 0]
},
"finger_back_left": {
"rotation": [0, -15, 0]
},
"finger_thumb_left": {
"rotation": [0, -20, 0]
},
"arm_right": {
"rotation": [-73.51921, -6.14051, 13.09658]
},
"finger_front_right": {
"rotation": [0, -5, 0]
},
"finger_back_right": {
"rotation": [0, 10, 0]
},
"finger_thumb_right": {
"rotation": [0, 25, 0]
},
"leg_left": {
"rotation": [-97.62567, -25.77605, 9.45845],
"position": [1.1, 1.65, -5]
},
"leg_left2": {
"rotation": [17.5, 0, 0]
},
"leg_right": {
"rotation": [-66.51084, 28.74673, 11.67459],
"position": [0, 2, -4]
},
"leg_right2": {
"rotation": [15, 0, 0]
},
"pupil_right": {
"position": [0, 0.1, 0]
}
}
},
"animation.quilladin.ground_idle": {
"loop": true,
"bones": {
@@ -197,166 +396,18 @@
},
"foot_right": {
"rotation": [15, 0, 0]
}
}
},
"animation.quilladin.blink": {
"animation_length": 0.16667,
"bones": {
"eyelid_right": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, -0.1],
"0.125": [0, 0, -0.1],
"0.1667": [0, 0, 0]
}
}
}
},
"animation.quilladin.cry": {
"animation_length": 1.5,
"bones": {
"neck": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [10, 0, 0],
"1.25": [10, 0, 0],
"1.5": [0, 0, 0]
}
"eye_left": {
"position": [0, 0, 0.1]
},
"mouth": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, -2, 0],
"1.25": [0, -2, 0],
"1.5": [0, 0, 0]
}
"eye_right": {
"position": [0, 0, 0.1]
},
"mouth2": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, -5, 0],
"1.25": [0, -5, 0],
"1.5": [0, 0, 0]
}
"mouth_closed_smile": {
"position": [0, 0, 0.1]
},
"jaw": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, -3, 0],
"1.25": [0, -3, 0],
"1.5": [0, 0, 0]
}
},
"head": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [-15, 0, 0],
"1.25": [-15, 0, 0],
"1.5": [0, 0, 0]
}
},
"head2": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [-15, 0, 0],
"1.25": [-15, 0, 0],
"1.5": [0, 0, 0]
}
},
"mouth_closed2": {
"position": {
"0.25": [0, 0, -0.1],
"0.3333": [0, 0, 0],
"1.1667": [0, 0, 0],
"1.25": [0, 0, -0.1]
}
},
"mouth_open2": {
"position": {
"0.0": [0, 0, 0.1],
"0.25": [0, 0, 0],
"1.25": [0, 0, 0],
"1.5": [0, 0, 0.1]
}
},
"head3": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [-15, 0, 0],
"1.25": [-15, 0, 0],
"1.5": [0, 0, 0]
}
},
"mouth_closed3": {
"position": {
"0.25": [0, 0, -0.1],
"0.3333": [0, 0, 0],
"1.1667": [0, 0, 0],
"1.25": [0, 0, -0.1]
}
},
"mouth_open3": {
"position": {
"0.0": [0, 0, 0.1],
"0.25": [0, 0, 0],
"1.25": [0, 0, 0],
"1.5": [0, 0, 0.1]
}
},
"mouth_closed": {
"position": {
"0.25": [0, 0, 0],
"0.3333": [0, 0, 0.1],
"1.1667": [0, 0, 0.1],
"1.25": [0, 0, 0]
}
},
"mouth_open": {
"position": {
"0.0": [0, 0, 0],
"0.25": [0, 0, -0.1],
"1.25": [0, 0, -0.1],
"1.5": [0, 0, 0]
}
},
"torso": {
"rotation": {
"0.0": ["-5+math.sin(q.anim_time*90*6+45)*8", 0, 0],
"0.25": ["-5+math.sin(q.anim_time*90*6+45)*8", 0, 0],
"0.3333": ["-8.29+math.sin(q.anim_time*90*3+95)*6", 0, 0],
"1.0": ["-8.29+math.sin(q.anim_time*90*3)*2", 0, 0],
"1.5": [0, 0, 0]
}
},
"spike_left": {
"rotation": {
"0.0": [0, 0, "-10+math.sin(q.anim_time*90*6+45)*8"],
"0.25": [0, 0, "-10+math.sin(q.anim_time*90*6+45)*8"],
"0.3333": [0, 0, "-20+math.sin(q.anim_time*90*3+95)*8"],
"1.0": [0, 0, "-20+math.sin(q.anim_time*90*3+95)*8"],
"1.5": [0, 0, 0]
}
},
"spike_right": {
"rotation": {
"0.0": [0, 0, "10-math.sin(q.anim_time*90*6+45)*8"],
"0.25": [0, 0, "10-math.sin(q.anim_time*90*6+45)*8"],
"0.3333": [0, 0, "20-math.sin(q.anim_time*90*3+95)*8"],
"1.0": [0, 0, "20-math.sin(q.anim_time*90*3+95)*8"],
"1.5": [0, 0, 0]
}
}
},
"sound_effects": {
"0.1667": {
"effect": "pokemon.quilladin.cry"
"mouth_closed_neutral": {
"position": [0, 0, -0.1]
}
}
}
@@ -147,21 +147,54 @@
}
},
"animation.fennekin.blink": {
"animation_length": 0.125,
"animation_length": 0.1667,
"bones": {
"eyelid_right": {
"position": {
"0.0": [-0.1, 0, -0.1],
"0.0417": [-0.1, 0, -0.1],
"0.0833": [0, 0, 0]
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0.1, 0, -0.1],
"0.0417": [0.1, 0, -0.1],
"0.0833": [0, 0, 0]
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eye_left": {
"position": {
"0.0": [-0.1, 0, 0.1],
"0.1667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0.1, 0, 0.1],
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_ditto": {
"position": {
"0.0": [0, 0, 0.1],
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"eyes_blink_ditto": {
"position": {
"0.0": [0, 0, -0.1],
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.fennekin.ditto_face": {
"loop": true,
"bones": {
"face": {
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
},
@@ -182,27 +215,31 @@
"0.5833": [0, 0, 0]
}
},
"jaw": {
"rotation": {
"0.0": [0, 0, 0],
"0.0833": [64.27, 0, 0],
"0.125": [70, 0, 0],
"0.1667": [38.9, 0, 0],
"0.2083": [35, 0, 0],
"0.25": [38.75, 0, 0],
"0.2917": [65.58, 0, 0],
"0.3333": [70, 0, 0],
"0.4167": [65.76, 0, 0],
"0.5417": [3.9, 0, 0],
"0.5833": [0, 0, 0]
}
},
"mouth_top": {
"mouth_open": {
"position": {
"0.0": [0, 0, 0],
"0.0417": [0, -1, 0],
"0.5": [0, -1, 0],
"0.5417": [0, 0, 0]
"0.0417": {"pre": [0, 0, 0], "post": [0, -1, 0]},
"0.1667": {"pre": [0, -1, 0], "post": [0, 0, 0]},
"0.2083": {"pre": [0, 0, 0], "post": [0, -1, 0]},
"0.5417": {"pre": [0, -1, 0], "post": [0, 0, 0]}
}
},
"mouth_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
"0.2083": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"0.5417": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"0.2083": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.5417": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
},
@@ -238,23 +275,30 @@
},
"ear_ruff_shock_left": {
"rotation": [0, 0, 0]
},
"ear_ruff_right": {
"rotation": [0, 0, -2.5]
}
}
},
"animation.fennekin.shock": {
"loop": true,
"bones": {
"pupil_left2": {
"scale": [0.7, 0.7, 1]
"pupil_left": {
"rotation": [-2.1, 0, 0],
"position": [0, 0.75, 0.028],
"scale": [0.7, 0.8, 1]
},
"mouth_top": {
"mouth_open": {
"position": [0, -1, 0]
},
"jaw": {
"rotation": [65, 0, 0]
},
"pupil_right2": {
"scale": [0.7, 0.7, 1]
"pupil_right": {
"rotation": [-2.1, 0, 0],
"position": [0, 0.75, 0.028],
"scale": [0.7, 0.8, 1]
}
}
},
@@ -272,6 +316,12 @@
},
"ear_ruff_shock_right": {
"scale": 0
},
"eye_neutral_left": {
"position": [-0.1, 0, 0.1]
},
"eye_neutral_right": {
"position": [0.1, 0, 0.1]
}
}
},
@@ -289,6 +339,12 @@
},
"ear_ruff_shock_right": {
"scale": 0
},
"eye_neutral_left": {
"position": [-0.1, 0, 0.1]
},
"eye_neutral_right": {
"position": [0.1, 0, 0.1]
}
}
},
@@ -298,7 +354,7 @@
"eyelid_happy_left": {
"position": [0.1, 0, -0.1]
},
"mouth_top": {
"mouth_open": {
"position": [0, -1, 0]
},
"jaw": {
@@ -312,23 +368,12 @@
},
"ear_ruff_shock_right": {
"scale": 0
}
}
},
"animation.fennekin.blush": {
"loop": true,
"bones": {
"blush_left": {
"position": [0.1, 0, 0]
},
"blush_right": {
"position": [-0.1, 0, 0]
"eye_neutral_left": {
"position": [-0.1, 0, 0.1]
},
"ear_ruff_shock_left": {
"scale": 0
},
"ear_ruff_shock_right": {
"scale": 0
"eye_neutral_right": {
"position": [0.1, 0, 0.1]
}
}
},
@@ -346,6 +391,12 @@
},
"ear_ruff_shock_right": {
"scale": 0
},
"eye_neutral_left": {
"position": [-0.1, 0, 0.1]
},
"eye_neutral_right": {
"position": [0.1, 0, 0.1]
}
}
}
@@ -4,36 +4,85 @@
"animation.braixen.ground_idle": {
"loop": true,
"bones": {
"torso": {
"rotation": [2.5, 0, 0]
"neck": {
"rotation": ["10-math.sin(q.anim_time*90*2.5)*2", 0, 0]
},
"head": {
"rotation": ["2.5+math.sin(q.anim_time*90*2.5+45)*2", 0, 0]
},
"ear_ruff_right": {
"rotation": [0, 5, "-1-math.sin(q.anim_time*90*2.5+45)*1"]
},
"ear_ruff_right2": {
"rotation": [0, 10, "-math.sin(q.anim_time*90*2.5)*1"]
},
"ear_ruff_right3": {
"rotation": [0, 10, "-math.sin(q.anim_time*90*2.5-45)*1"]
},
"ear_ruff_left": {
"rotation": [0, -2.5, "1+math.sin(q.anim_time*90*2.5+45)*1"]
},
"ear_ruff_left2": {
"rotation": [0, -10, "math.sin(q.anim_time*90*2.5)*1"]
},
"ear_ruff_left3": {
"rotation": [0, -10, "math.sin(q.anim_time*90*2.5-45)*1"]
},
"arm_right": {
"rotation": [0.95384, "12.1536-math.sin(q.anim_time*90*2.5+45)*2", -42.42961]
},
"arm_right2": {
"rotation": [-0.02642, -32.49865, 0.04926]
},
"arm_left": {
"rotation": [0.95384, "-12.1536+math.sin(q.anim_time*90*2.5+45)*2", 42.42961]
},
"arm_left2": {
"rotation": [-0.02642, 32.49865, -0.04926]
},
"tail": {
"rotation": ["5+math.sin(q.anim_time*90*2.5)*2", "math.sin(q.anim_time*90*1.25-90)*4", "math.sin(q.anim_time*90*1.25-90)*2"],
"position": [0, 0, 0.5]
},
"tail2": {
"rotation": [0, 0, "math.sin(q.anim_time*90*1.25-45)*4"]
},
"tail3": {
"rotation": ["math.sin(q.anim_time*90*2.5-90)*2", 0, 0]
},
"tail4": {
"rotation": ["math.sin(q.anim_time*90*2.5-135)*2", 0, 0]
},
"finger_middle_right": {
"rotation": [0, 0, -10]
},
"finger_middle_left": {
"rotation": [0, 0, 10]
},
"waist": {
"rotation": [-5, 0, 0]
},
"chest": {
"rotation": [2.5, 0, 0]
},
"arm_left": {
"rotation": [0, 7.5, 70]
},
"arm_left2": {
"rotation": [-5, 37.5, -2.5]
},
"hand_left": {
"rotation": [57.5, -10, 7.5]
"rotation": [0, 0, -25]
},
"neck": {
"rotation": [-5, 0, 0]
"finger_front_left": {
"rotation": [0, 0, 25]
},
"head": {
"rotation": [12.5, 0, 0]
"finger_back_left": {
"rotation": [0, 0, 22.5]
},
"tail": {
"hand_right": {
"rotation": [0, 0, 25]
},
"finger_front_right": {
"rotation": [0, 0, -25]
},
"finger_back_right": {
"rotation": [0, 0, -22.5]
},
"skirt_front2": {
"rotation": [5, 0, 0]
},
"stick_tail": {
"rotation": [-5, 0, 0]
},
"leg_left": {
"rotation": [0.88045, -9.96156, -5.07673]
},
@@ -49,93 +98,41 @@
"leg_right3": {
"rotation": [0.00039, 5.00185, -5.99069]
},
"finger_front_left": {
"rotation": [9.99527, 9.84653, 30.20756]
},
"finger_back_left": {
"rotation": [-4.26175, -9.05478, 25.33761]
},
"finger_middle_left": {
"rotation": [0, 0, 27.5]
},
"arm_right": {
"rotation": [65, 22.5, -45],
"position": [0, 0, 0.5]
},
"arm_right2": {
"rotation": [-15, -82.5, 15]
},
"hand_right": {
"rotation": [-10, -22.5, 70]
},
"finger_front_right": {
"rotation": [9.99527, -9.84653, -30.20756]
},
"finger_middle_right": {
"rotation": [0, 0, -27.5]
},
"finger_back_right": {
"rotation": [-4.26175, 9.05478, -25.33761]
},
"ear_ruff_left2": {
"rotation": [0, -7.5, 0]
},
"ear_ruff_left3": {
"rotation": [0, -7.5, 0]
},
"ear_ruff_left4": {
"rotation": [0, -7.5, 0]
},
"skirt_front2": {
"rotation": [-2.5, 0, 0]
},
"foot_right": {
"rotation": [1, 0, 0]
},
"ear_ruff_left": {
"rotation": [0, -7.5, 0]
"skirt_left2": {
"rotation": [0, 0, 15]
},
"ear_ruff_right": {
"rotation": [0, 7.5, 0]
"skirt_right2": {
"rotation": [0, 0, -15]
},
"ear_ruff_right2": {
"rotation": [0, 7.5, 0]
"wand": {
"scale": 0
},
"ear_ruff_right3": {
"rotation": [0, 7.5, 0]
},
"ear_ruff_right4": {
"rotation": [0, 7.5, 0]
},
"skirt_front_left": {
"rotation": [0, 0, 10]
},
"skirt_front_right": {
"rotation": [0, 0, -10]
"wand_tail": {
"rotation": [-10, 0, 0]
},
"ear_ruff_shock_left": {
"scale": 0
},
"ear_ruff_shock_right": {
"scale": 0
},
"wand": {
"scale": 0
}
}
},
"animation.braixen.battle_idle": {
"loop": true,
"animation_length": 0.875,
"bones": {
"body": {
"rotation": [0, -52.5, 0],
"position": [-0.5, -2.05, 0]
},
"torso": {
"rotation": [15, -10, 0]
},
"waist": {
"rotation": [-2.5, -2.5, 0]
"rotation": [5, 0, 0]
},
"chest": {
"rotation": [-5, 2.5, 0]
@@ -162,10 +159,10 @@
"rotation": [0, -10, 0]
},
"arm_right": {
"rotation": [-60.09473, -14.92923, -20.56425]
"rotation": [-35.09473, -47.42923, -40.56425]
},
"arm_right2": {
"rotation": [0, -45, 0]
"rotation": [0, -40, 0]
},
"hand_right": {
"rotation": [0, 27.5, 15]
@@ -180,10 +177,10 @@
"rotation": [0, 0, -77.5]
},
"neck": {
"rotation": [0, 32.5, -7.5]
"rotation": [0, 5, 0]
},
"head": {
"rotation": [-7.5, 20, -5]
"rotation": [-10, 0, 0]
},
"ear_ruff_left2": {
"rotation": [0, -12.5, 0]
@@ -216,32 +213,28 @@
"scale": 0
},
"leg_left": {
"rotation": [-0.5, -35, -26],
"position": [1, 0, 0]
"rotation": [5.38152, -19.291, -15.91527]
},
"leg_left2": {
"rotation": [10, 0, 0]
"rotation": [25, 0, 0]
},
"leg_left3": {
"rotation": [-22.5, 0, 0]
"rotation": [-16.28567, 14.26008, -10.25103]
},
"foot_left": {
"rotation": [29.78634, -18.01295, 11.28749],
"position": [0, -0.5, 0]
"rotation": [-12.32417, 1.61888, 12.39638]
},
"leg_right": {
"rotation": [-7.80674, 36.44232, 19.22515],
"position": [-1, -0.75, -0.75]
"rotation": [-27.5, 0, 0]
},
"leg_right2": {
"rotation": [29.75489, -5.05904, 8.04401]
"rotation": [27.25489, -5.05904, 5.54401]
},
"leg_right3": {
"rotation": [-30.5, -2, -1]
"rotation": [-25, 0, 0]
},
"foot_right": {
"rotation": [22.5, 20, -10],
"position": [0, -0.5, 0]
"rotation": [24.78729, 3.74196, -6.50446]
},
"ear_ruff_right2": {
"rotation": [0, 12.5, 0]
@@ -252,111 +245,31 @@
"ear_ruff_right4": {
"rotation": [0, 17.5, 0]
},
"stick_hand": {
"rotation": [90, 10, 0],
"position": [6.5, -1, -0.5]
},
"skirt_front_left": {
"rotation": [0, 0, 7.5]
},
"skirt_front_right": {
"rotation": [0, 0, -2.5]
},
"fire": {
"rotation": [-7.24721, -1.93597, -14.87738]
},
"wand": {
"rotation": [22.01816, -4.75113, 11.57518],
"position": [14, -7, -11.5]
},
"wand_tail": {
"scale": 0
},
"ear_ruff_shock_left": {
"scale": 0
},
"ear_ruff_shock_right": {
"scale": 0
},
"skirt": {
"rotation": [-5, 0, 0]
},
"body_wand": {
"rotation": [0, -52.5, 0],
"position": [-0.5, -2.05, 0]
},
"torso_wand": {
"rotation": [15, -10, 0]
},
"waist_wand": {
"rotation": [-2.5, -2.5, 0]
},
"chest_wand": {
"rotation": [-5, 2.5, 0]
},
"arm_wand": {
"rotation": [-60.09473, -14.92923, -20.56425]
},
"arm2_wand": {
"rotation": [0, -45, 0]
},
"hand_wand": {
"rotation": [0, 27.5, 15]
},
"wand": {
"rotation": [90, 10, 0],
"position": [6.5, -1, -0.5]
}
}
},
"animation.braixen.blink": {
"animation_length": 0.1667,
"bones": {
"eyelid_left": {
"position": {
"0.0": [0.1, 0, -0.1],
"0.125": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [-0.1, 0, -0.1],
"0.125": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.braixen.cry": {
"animation_length": 1,
"bones": {
"head": {
"rotation": {
"0.0": [0, 0, 0],
"0.0417": [-2.05, 0, 0],
"0.0833": [-2.7, 0, 0],
"0.1667": [4, 0, 0],
"0.2083": [3.72, 0, 0],
"0.375": [-2.38, 0, 0],
"0.4167": [-2.7, 0, 0],
"0.5": [-2.4, 0, 0],
"0.6667": [-0.3, 0, 0],
"0.75": [0, 0, 0]
}
},
"jaw": {
"rotation": {
"0.0": [0, 0, 0],
"0.0417": [27.2, 0, 0],
"0.0833": [30, 0, 0],
"0.1667": [19, 0, 0],
"0.2083": [17.65, 0, 0],
"0.3333": [57.56, 0, 0],
"0.375": [60, 0, 0],
"0.4167": [56.99, 0, 0],
"0.7083": [4.23, 0, 0],
"0.7917": [0, 0, 0]
}
},
"fangs": {
"position": {
"0.0": [0, 0, 0],
"0.0417": [0, -0.5, 0],
"0.625": [0, -0.5, 0],
"0.6667": [0, 0, 0]
}
}
},
"sound_effects": {
"0.0": {
"effect": "pokemon.braixen.cry"
}
}
},
@@ -478,20 +391,255 @@
"finger_back_right": {
"rotation": [0, 0, -22.5]
},
"stick_hand": {
"scale": 0
},
"ear_ruff_left4": {
"rotation": [0, 12.5, 0]
},
"ear_ruff_right4": {
"rotation": [0, -12.5, 0]
},
"wand": {
"scale": 0
},
"ear_ruff_shock_left": {
"scale": 0
},
"ear_ruff_shock_right": {
"scale": 0
}
}
},
"animation.braixen.blink": {
"animation_length": 0.1667,
"bones": {
"eyelid_left": {
"position": {
"0.0": [0.1, 0, -0.1],
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [-0.1, 0, -0.1],
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eye_left": {
"position": {
"0.0": [-0.1, 0, 0.1],
"0.1667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0.1, 0, 0.1],
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
}
}
}
},
"animation.braixen.cry": {
"animation_length": 1,
"bones": {
"head": {
"rotation": {
"0.0": [0, 0, 0],
"0.0417": [-2.05, 0, 0],
"0.0833": [-2.7, 0, 0],
"0.1667": [4, 0, 0],
"0.2083": [3.72, 0, 0],
"0.375": [-2.38, 0, 0],
"0.4167": [-2.7, 0, 0],
"0.5": [-2.4, 0, 0],
"0.6667": [-0.3, 0, 0],
"0.75": [0, 0, 0]
}
},
"jaw": {
"rotation": {
"0.0": [0, 0, 0],
"0.0417": [27.2, 0, 0],
"0.0833": [30, 0, 0],
"0.1667": [19, 0, 0],
"0.2083": [17.65, 0, 0],
"0.3333": [57.56, 0, 0],
"0.375": [60, 0, 0],
"0.4167": [56.99, 0, 0],
"0.7083": [4.23, 0, 0],
"0.7917": [0, 0, 0]
}
},
"mouth_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
"0.8333": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
}
},
"mouth_open_ditto": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
"0.8333": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
}
}
},
"sound_effects": {
"0.0": {
"effect": "pokemon.braixen.cry"
}
}
},
"animation.braixen.ditto_face": {
"loop": true,
"bones": {
"face": {
"scale": 0
},
"face_ditto": {
"position": [0, 0, -0.1]
}
}
},
"animation.braixen.pose": {
"loop": true,
"bones": {
"body": {
"rotation": [-12.5, -30, 0]
},
"waist": {
"rotation": [0, 5, 0]
},
"chest": {
"rotation": [5, 0, 0]
},
"arm_left": {
"rotation": [12.25294, -38.3808, 35.72104]
},
"arm_left2": {
"rotation": [0, 5, -15]
},
"hand_left": {
"rotation": [0, 0, -15]
},
"neck": {
"rotation": [10, 0, 0]
},
"head": {
"rotation": [12.48848, -0.54094, 2.44081]
},
"jaw": {
"rotation": [70, 0, 0]
},
"ear_ruff_left2": {
"rotation": [0, -12.5, 0]
},
"ear_ruff_left3": {
"rotation": [0, -7.5, 0]
},
"ear_ruff_left4": {
"rotation": [0, 12.5, 0]
"rotation": [0, -22.5, 0]
},
"tail": {
"rotation": [7.08681, -3.21132, 14.65993]
},
"tail2": {
"rotation": [10, 0, 0]
},
"leg_left": {
"rotation": [13.9042, 5.68422, -21.80633]
},
"leg_left3": {
"rotation": [17.5, 0, 0]
},
"foot_left": {
"rotation": [47.5, 0, 0],
"position": [0, 0, -1]
},
"ear_ruff_right": {
"rotation": [0, -12.5, 0]
},
"ear_ruff_right2": {
"rotation": [0, 7.5, 0]
},
"ear_ruff_right3": {
"rotation": [0, 7.5, 0]
},
"ear_ruff_right4": {
"rotation": [0, 5, 0]
},
"arm_right": {
"rotation": [41.62332, 22.64192, -3.4873]
},
"arm_right2": {
"rotation": [-26.43596, -58.95768, 35.12627]
},
"hand_right": {
"rotation": [2.5, 0, 17.5]
},
"finger_front_right": {
"rotation": [0, -7.5, -65]
},
"finger_middle_right": {
"rotation": [0, 0, -62.5]
},
"finger_back_right": {
"rotation": [0, 12.5, -67.5]
},
"body_wand": {
"rotation": [-12.5, -30, 0]
},
"waist_wand": {
"rotation": [0, 5, 0]
},
"chest_wand": {
"rotation": [5, 0, 0]
},
"arm_wand": {
"rotation": [41.62332, 22.64192, -3.4873]
},
"arm2_wand": {
"rotation": [-26.43596, -58.95768, 35.12627]
},
"hand_wand": {
"rotation": [2.5, 0, 17.5]
},
"wand": {
"rotation": [-87.5, 0, 0],
"position": [6, -1, -6]
},
"fire": {
"rotation": [47.5, 0, 0]
},
"wand_tail": {
"scale": 0
},
"leg_right": {
"rotation": [-16.24074, 6.60796, 21.55613]
},
"leg_right2": {
"rotation": [35, 0, 0]
},
"leg_right3": {
"rotation": [-47.5, 0, 0]
},
"foot_right": {
"rotation": [27.5, 0, 0]
},
"pupil_right": {
"position": [-1, 0, 0]
},
"ear_ruff_shock_left": {
"scale": 0
},
"ear_ruff_shock_right": {
"scale": 0
},
"ear_ruff_right4": {
"rotation": [0, -12.5, 0]
}
}
}

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