Compare commits

...
Author SHA1 Message Date
Lily 1e261966ed run button works 2024-02-28 19:07:26 -05:00
Apion a270371632 Merge branch 'sturdier_tumblestones' into 'main'
fix tumblestone blocks being breakable without a pickaxe

See merge request cable-mc/cobblemon!892
2024-02-28 18:23:21 +00:00
LilyandApion a9caf92d2f fix tumblestone blocks being breakable without a pickaxe 2024-02-28 18:23:21 +00:00
Apion ff4d9ae208 Merge branch 'gimmighoul_gholdengo' into 'main'
Add Gimmighoul, Gholdengo, Relic Coins and Gilded Chests

See merge request cable-mc/cobblemon!888
2024-02-28 02:03:37 +00:00
LilyandApion a87d522f6d Add Gimmighoul, Gholdengo, Relic Coins and Gilded Chests 2024-02-28 02:03:37 +00:00
Hiroku dca6b5273d Merge branch 'FossilAssetUpdate2' into 'main'
New animation assets for fetuses

See merge request cable-mc/cobblemon!889
2024-02-26 07:57:15 +00:00
JazzMcNade 2e8483cdc7 Corrected comment, fixed machine not dropping fossils when destroyed while not started. 2024-02-26 01:29:11 -06:00
Hiroku 6b1c2e2074 Merge branch 'showdown_gen9dlc' into 'main'
Update Showdown with Gen9 DLC.

See merge request cable-mc/cobblemon!890
2024-02-26 03:52:34 +00:00
Segfault Guy 8af5b5e07a Update Showdown with Gen9 DLC. 2024-02-25 22:44:27 -05:00
Hiroku 7ae19ca774 Merge branch 'issue-763' into 'main'
Stop Rails from being Spawnable tiles

Closes #763

See merge request cable-mc/cobblemon!881
2024-02-26 03:13:27 +00:00
Dhyan PatelandHiroku 830f00553e Stop Rails from being Spawnable tiles 2024-02-26 03:13:27 +00:00
Hiroku c87f56c83f Merge branch 'lang-fixes' into 'main'
brought a couple inconsistent lang keys into consistency

See merge request cable-mc/cobblemon!887
2024-02-25 02:06:17 +00:00
tmetcalfe89 4478532bcb brought a couple inconsistent lang keys into consistency 2024-02-24 18:02:02 -08:00
Hiroku 184348d6fa Merge branch 'lazy-psf' into 'main'
made the spawns lazy so we can ref the object's other properties without violating the lateinit

Closes #765

See merge request cable-mc/cobblemon!886
2024-02-23 23:31:03 +00:00
Hiroku 04d288ed7e Merge branch 'issue-760' into 'main'
Fix Medicinal Brews / Potions Stacking in Brewing Stand

See merge request cable-mc/cobblemon!876
2024-02-23 23:29:52 +00:00
Dhyan PatelandHiroku 0d5cce730e Fix Medicinal Brews / Potions Stacking in Brewing Stand 2024-02-23 23:29:51 +00:00
tmetcalfe89 3e01535203 license 2024-02-23 12:03:45 -08:00
tmetcalfe89 f0d99a9d83 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into lazy-psf 2024-02-23 11:42:40 -08:00
tmetcalfe89 b4eb46d632 it's lazy, but it can change 2024-02-23 11:42:35 -08:00
Hiroku 7e52336255 Merge branch 'InconsistentHpBarFix' into 'main'
InconsistentHpBarFix

Closes #761

See merge request cable-mc/cobblemon!875
2024-02-23 02:39:42 +00:00
Hiroku 2b40b5b689 Merge branch 'feather-dusting' into 'main'
Feathers

See merge request cable-mc/cobblemon!882
2024-02-23 02:39:01 +00:00
tmetcalfe89 da889f220b made the spawns lazy so we can ref the object's other properties without violating the lateinit 2024-02-22 14:55:29 -08:00
dhi_holo 41db2a53ce Update en_us.json
just adding the feather tag to the translations so EMI stops complaining about it (and fixing a typo)
2024-02-22 11:28:58 +10:00
dhi_holo 85d8779818 The Sound of... Feathers?
it seems to be working correctly, so let's ship it out
2024-02-22 11:27:54 +10:00
Hiroku d817ce1471 Merge branch 'gui-mod-compat-fixes' into 'main'
Client screen crash fixes with other mods

See merge request cable-mc/cobblemon!885
2024-02-21 11:44:38 +00:00
LiciousandHiroku ce09b66db5 Client screen crash fixes with other mods 2024-02-21 11:44:38 +00:00
Hiroku d0c666a20d Merge branch 'main' into 'feather-dusting'
# Conflicts:
#   CHANGELOG.md
2024-02-21 10:03:38 +00:00
Hiroku 04cef915e4 Merge branch 'tagging-youre-it' into 'main'
Big Tags

See merge request cable-mc/cobblemon!884
2024-02-21 09:50:44 +00:00
dhi_holo e50412443e Update CHANGELOG.md
Removed weird incorrect text from Type Gem changelog entry, mentioned additions from this branch.
2024-02-21 19:11:24 +10:00
dhi_holo 3fe1f87f18 apricorn trapdoor now doesn't look jank when opening
just changed the blockstate from the oak trapdoor style to the spruce trapdoor style, so the pokeball direction stays consistent when opened or closed
2024-02-21 19:08:38 +10:00
dhi_holo 5a0fc199ff Create feathers.json
item tag, since I forgot that would be smart to have
2024-02-21 17:35:07 +10:00
dhi_holo beb769c2a5 Update CobblemonItemGroups.kt
small tweak to how the items are placed for gaurenteed consistency
2024-02-21 17:31:29 +10:00
dhi_holo a7b6fae4ed gems, fang, claw, and armors get tagged
Type Gems are now considered held items, and four evolution items are considered evolution items (by tags)
2024-02-21 17:28:00 +10:00
dhi_holo af2ff7bbfa Gems
Type Gems given an item tag, and moved from Evolution Items to Archeology and Held Items
2024-02-21 17:11:17 +10:00
dhi_holo 4f3575b2c6 Poke Ball Materials and Bud Item Tag
adds the tumblestone clusters and buds to the item tags, and adds fire stone ore to each ore tag, but primarily

Redoes every Poké Ball recipe (besides Master) to use tags to handle the tier material, allowing datapacks to easily add alternate recipes besides Copper, Iron, Gold, or Diamonds
2024-02-21 16:41:41 +10:00
dhi_holo 98c248ef13 corrections
renaming some stuff to be prepared for the next step of this insane idea
2024-02-21 15:34:20 +10:00
dhi_holo 4a2c69d47c Tags on top of Tags
Added a very large amount of tags.
The different tiers of Poké balls, also the Apricorn balls so it's easier for people to see what balls count for that advancement, different healing and battle item types, some evolution item sets which made sense to make tags (may add more later, these ones were just the obvious ones to make thing easier for future), the three colours for tumblestones, machine blocks, as well as adding the fence gate item tag, and adding the new tumblestone stuff to the pickaxe tag (although they can still be mined with an axe, probably something that needs fixing)

Mod loader tags were not tested on Forge, due to a crash involving CobblemonEntities, but Fabric works all nicely
2024-02-21 15:29:55 +10:00
dhi_holo c23cb644d9 Update CHANGELOG.md
grr evil file
2024-02-21 09:43:33 +10:00
dhi_holo a8b12cfca3 Feathers
Adds the six EV Feathers, hopefully they work first try :)
2024-02-21 09:32:05 +10:00
Apion b489e747bb Merge branch 'type_gem' into 'main'
added type gems

See merge request cable-mc/cobblemon!880
2024-02-20 13:22:41 +00:00
Lily 08f957e33b Update CHANGELOG.md 2024-02-19 21:32:30 -05:00
Lily e17d38c53a added type gems 2024-02-19 21:24:29 -05:00
apion 0397e39735 I have become the very thing I swore to destroy (Pushing a license to main D:) 2024-02-19 20:18:55 -05:00
Apion 6ca1d23f45 Merge branch 'no_more_pick_block' into 'main'
disallow pick-stacking blocks that are part of a multiblock structure to prevent weird issues with NBT copying

See merge request cable-mc/cobblemon!874
2024-02-19 23:38:26 +00:00
JazzMcNade 44def2be76 Fossil is returned if the machine is broken before completion. Restoration Block now uses glass sounds. Mobs no longer attempt to pathfind through the restoration tank. 2024-02-17 20:37:05 -06:00
JazzMcNade 507f70c2d5 Fixed tank missing blockstates, fixed hoppers inserting into tank 2024-02-17 18:46:02 -06:00
JazzMcNade d91118d05f Updated helix fossil item image 2024-02-17 14:17:34 -06:00
JazzMcNade 07d8e6ed09 Adjusted fetus offset and scaling 2024-02-16 21:20:09 -06:00
Hiroku 64d160020b Merge branch 'issue-745' into 'main'
Sobble Line Can Swim and Breathe Underwater

Closes #745

See merge request cable-mc/cobblemon!878
2024-02-16 06:36:50 +00:00
Dhyan PatelandHiroku fb4c80f68c Sobble Line Can Swim and Breathe Underwater 2024-02-16 06:36:50 +00:00
Paul 2b5433f9da Added hit effect for pokemon receiving battle damage 2024-02-16 15:37:52 +10:00
JazzMcNade 9bad141c3f Added remaining fetus animations, updated embryo animations 2024-02-15 21:57:42 -06:00
Paul fe8e4dcaff Improved Pokémon pathfinding so they don't run through cactus and such so recklessly 2024-02-16 12:24:58 +10:00
Paul e0bd6766fc Fixed basculin stripe spawning 2024-02-16 11:37:16 +10:00
Paul 4da800d396 Fixed Arbok patterns not being used properly in spawn files 2024-02-16 11:19:24 +10:00
JazzMcNade f3246ae14a Updated fossil sprites, refactored Galar fossil names 2024-02-15 01:33:11 -06:00
JazzMcNade 47f87b1be3 Rearranged pokemon creation so that currentHealth is assigned after ivs and evs are set 2024-02-13 00:08:04 -06:00
Lily da6a09c942 disallow pick-stacking blocks that are part of a multiblock structure to prevent weird issues with NBT copying 2024-02-12 17:40:39 -05:00
500 changed files with 13804 additions and 580 deletions
+4 -1
View File
@@ -33,4 +33,7 @@ common/src/main/resources/assets/cobblemon/showdown
# Generated files
*/generated/resources/*
/fabric/src/generated/resources/cobblemon-common.accesswidener
/.ignored/
/.ignored/
# MacOS
.DS_Store
+17
View File
@@ -20,6 +20,14 @@
- Added effects for many Poké Balls when sending out Pokémon or capturing.
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
- Added simple move animations for Pokémon in battle with a proof of concept for more complicated animations.
- Added the EV Boosting Feathers.
- Added Type Gems.
- Added various new tags for searchability and better compatibility.
- Added Gilded Chests, available in all Apricorn colors.
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks.
- Added Gimmighoul.
- Using Relic Coins, you can increase Gimmighoul's Coin Stash. Upon reaching 999, it can be evolved into Gholdengo.
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. Who knows what might happen if it fills up?
### Changes
- Pokémon now transition more smoothly between different poses.
@@ -32,6 +40,8 @@
- Updated movesets to add Gen 9 DLC moves.
- Apricorn Sprouts can now be planted directly on Apricorn leaves to create a new Apricorn of the same color.
- Added tooltips to interaction GUIs to make it clearer what they do.
- Poké Ball recipes now use tags for their center ingredient, rather than specificied Copper Ingot, Iron Ingot, Gold Ingot, and Diamond, allowing for further datapack customisation.
- Using the run button in battle will now actually flee the battle.
### Fixes
- Re-added the recipe for the Iron Vitamin.
@@ -46,6 +56,12 @@
- Fixed Poké Balls freezing in an open state if you look away when it's meant to close.
- Adds a translation string name to the Empty Pokeball entity.
- Fixed very many issues with Bedrock particle effects.
- Fixed Arbok patterns not being as specific in spawning as they were intended.
- Fixed Pokémon not avoiding danger at all when pathfinding.
- Fixed Sobble line not being able to swim or breathe underwater.
- Fixed incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
- Fixed incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
- Fixed an issue that allowed Pokemon to spawn on rails.
### Developer
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
@@ -57,6 +73,7 @@
- Made PokemonProperties.parse more interoperable with Java.
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
### Datapack & Resourcepack Creators
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonItems;
import net.minecraft.entity.mob.PiglinBrain;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PiglinBrain.class)
public class PiglinBarterMixin {
@Inject(method = "acceptsForBarter", at = @At(value = "RETURN"), cancellable = true)
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
if(!ci.getReturnValue()) {
//TODO: Make a tag?
if(stack.isOf(CobblemonItems.RELIC_COIN_POUCH))
ci.setReturnValue(true);
}
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonItems;
import net.minecraft.entity.mob.PiglinEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(PiglinEntity.class)
public class PiglinEntityMixin {
@Redirect(method = "equipToOffHand", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isOf(Lnet/minecraft/item/Item;)Z"))
public boolean cobblemon$isValidBarteringItem(ItemStack stack, Item item) {
//TODO: Make a tag?
return stack.isOf(item) || stack.isOf(CobblemonItems.RELIC_COIN_POUCH);
}
}
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
import com.cobblemon.mod.common.api.events.CobblemonEvents.HELD_ITEM_UPDATED
import com.cobblemon.mod.common.api.events.CobblemonEvents.LEVEL_UP_EVENT
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
@@ -34,9 +35,7 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceCalculator
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.*
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
import com.cobblemon.mod.common.api.pokemon.stats.Generation8EvCalculator
@@ -94,6 +93,7 @@ import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
@@ -130,6 +130,7 @@ import net.minecraft.entity.data.TrackedDataHandlerRegistry
import net.minecraft.item.Items
import net.minecraft.item.NameTagItem
import net.minecraft.registry.RegistryKey
import net.minecraft.sound.SoundCategory
import net.minecraft.util.WorldSavePath
import net.minecraft.world.World
import org.apache.logging.log4j.LogManager
@@ -253,6 +254,7 @@ object Cobblemon {
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
SpeciesFeatures.types["integer"] = IntSpeciesFeatureProvider::class.java
SpeciesFeatures.register(
DataKeys.CAN_BE_MILKED,
@@ -45,6 +45,18 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
@JvmField
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.create(::GildedChestBlockEntity,
CobblemonBlocks.GILDED_CHEST,
CobblemonBlocks.BLUE_GILDED_CHEST,
CobblemonBlocks.YELLOW_GILDED_CHEST,
CobblemonBlocks.PINK_GILDED_CHEST,
CobblemonBlocks.BLACK_GILDED_CHEST,
CobblemonBlocks.WHITE_GILDED_CHEST,
CobblemonBlocks.GREEN_GILDED_CHEST,
CobblemonBlocks.GIMMIGHOUL_CHEST
).build(null))
@JvmField
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
@@ -151,11 +152,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
@JvmField
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
@JvmField
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
@JvmField
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.BIG_ROOT_SOUNDS)))
@JvmField
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
@@ -191,6 +192,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
@@ -198,6 +200,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
@@ -205,6 +208,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@@ -223,6 +227,99 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
@JvmField
val RELIC_COIN_POUCH = create(
"relic_coin_pouch",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f)
.nonOpaque(), true
)
)
@JvmField
val RELIC_COIN_SACK = create(
"relic_coin_sack",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f), false
))
@JvmField
val GILDED_CHEST = create(
"gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.RED
)
)
@JvmField
val BLUE_GILDED_CHEST = create(
"blue_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.BLUE
)
)
@JvmField
val BLACK_GILDED_CHEST = create(
"black_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.BLACK
)
)
@JvmField
val YELLOW_GILDED_CHEST = create(
"yellow_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.YELLOW
)
)
@JvmField
val WHITE_GILDED_CHEST = create(
"white_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.WHITE
)
)
@JvmField
val GREEN_GILDED_CHEST = create(
"green_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.GREEN
)
)
@JvmField
val PINK_GILDED_CHEST = create(
"pink_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.PINK
)
)
@JvmField
val GIMMIGHOUL_CHEST = create(
"gimmighoul_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.FAKE
)
)
@JvmField
val MONITOR = create(
"monitor",
@@ -255,7 +352,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
RestorationTankBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.sounds(BlockSoundGroup.GLASS)
.pistonBehavior(PistonBehavior.BLOCK)
.requiresTool()
.strength(5.0F, 6.0F)
@@ -290,17 +387,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
@JvmField
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val PASTURE = create(
@@ -441,7 +538,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
private fun berryBlock(name: String): BerryBlock {
val identifier = cobblemonResource("${name}_berry")
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(BlockSoundGroup.CROP).strength(0.2F)))
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(CobblemonSounds.BERRY_BUSH_SOUNDS).strength(0.2F)))
this.berries[identifier] = block
return block
}
@@ -229,6 +229,22 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val APRICORN_SIGN = this.create("apricorn_sign", SignItem(Item.Settings().maxCount(16), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
@JvmField
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
@JvmField
val GILDED_CHEST = this.create("gilded_chest", BlockItem(CobblemonBlocks.GILDED_CHEST, Item.Settings()))
@JvmField
val BLUE_GILDED_CHEST = this.create("blue_gilded_chest", BlockItem(CobblemonBlocks.BLUE_GILDED_CHEST, Item.Settings()))
@JvmField
val YELLOW_GILDED_CHEST = this.create("yellow_gilded_chest", BlockItem(CobblemonBlocks.YELLOW_GILDED_CHEST, Item.Settings()))
@JvmField
val PINK_GILDED_CHEST = this.create("pink_gilded_chest", BlockItem(CobblemonBlocks.PINK_GILDED_CHEST, Item.Settings()))
@JvmField
val BLACK_GILDED_CHEST = this.create("black_gilded_chest", BlockItem(CobblemonBlocks.BLACK_GILDED_CHEST, Item.Settings()))
@JvmField
val WHITE_GILDED_CHEST = this.create("white_gilded_chest", BlockItem(CobblemonBlocks.WHITE_GILDED_CHEST, Item.Settings()))
@JvmField
val GREEN_GILDED_CHEST = this.create("green_gilded_chest", BlockItem(CobblemonBlocks.GREEN_GILDED_CHEST, Item.Settings()))
@JvmField
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Settings()))
@JvmField
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
@@ -380,6 +396,18 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
@JvmField
val GENIUS_FEATHER = create("genius_feather", FeatherItem(Stats.SPECIAL_ATTACK))
@JvmField
val SWIFT_FEATHER = create("swift_feather", FeatherItem(Stats.SPEED))
@JvmField
val HEALTH_FEATHER = create("health_feather", FeatherItem(Stats.HP))
@JvmField
val RESIST_FEATHER = create("resist_feather", FeatherItem(Stats.DEFENCE))
@JvmField
val MUSCLE_FEATHER = create("muscle_feather", FeatherItem(Stats.ATTACK))
@JvmField
val CLEVER_FEATHER = create("clever_feather", FeatherItem(Stats.SPECIAL_DEFENCE))
@JvmField
val MEDICINAL_LEEK = create("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())))
@JvmField
val ROASTED_LEEK = create("roasted_leek", Item(Item.Settings().food(FoodComponent.Builder().snack().hunger(3).saturationModifier(0.3f).build())))
@@ -733,19 +761,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val ARMOR_FOSSIL = noSettingsItem("armor_fossil")
@JvmField
val BIRD_FOSSIL = noSettingsItem("bird_fossil")
val FOSSILIZED_BIRD = noSettingsItem("fossilized_bird")
@JvmField
val CLAW_FOSSIL = noSettingsItem("claw_fossil")
@JvmField
val COVER_FOSSIL = noSettingsItem("cover_fossil")
@JvmField
val DINO_FOSSIL = noSettingsItem("dino_fossil")
val FOSSILIZED_DINO = noSettingsItem("fossilized_dino")
@JvmField
val DOME_FOSSIL = noSettingsItem("dome_fossil")
@JvmField
val DRAKE_FOSSIL = noSettingsItem("drake_fossil")
val FOSSILIZED_DRAKE = noSettingsItem("fossilized_drake")
@JvmField
val FISH_FOSSIL = noSettingsItem("fish_fossil")
val FOSSILIZED_FISH = noSettingsItem("fossilized_fish")
@JvmField
val HELIX_FOSSIL = noSettingsItem("helix_fossil")
@JvmField
@@ -824,6 +852,50 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
// Misc
@JvmField
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
@JvmField
val RELIC_COIN = noSettingsItem("relic_coin")
@JvmField
val RELIC_COIN_POUCH = blockItem("relic_coin_pouch", CobblemonBlocks.RELIC_COIN_POUCH)
@JvmField
val RELIC_COIN_SACK = blockItem("relic_coin_sack", CobblemonBlocks.RELIC_COIN_SACK)
// Type Gems
@JvmField
val NORMAL_GEM = noSettingsItem("normal_gem")
@JvmField
val FIRE_GEM = noSettingsItem("fire_gem")
@JvmField
val WATER_GEM = noSettingsItem("water_gem")
@JvmField
val GRASS_GEM = noSettingsItem("grass_gem")
@JvmField
val ELECTRIC_GEM = noSettingsItem("electric_gem")
@JvmField
val ICE_GEM = noSettingsItem("ice_gem")
@JvmField
val FIGHTING_GEM = noSettingsItem("fighting_gem")
@JvmField
val POISON_GEM = noSettingsItem("poison_gem")
@JvmField
val GROUND_GEM = noSettingsItem("ground_gem")
@JvmField
val FLYING_GEM = noSettingsItem("flying_gem")
@JvmField
val PSYCHIC_GEM = noSettingsItem("psychic_gem")
@JvmField
val BUG_GEM = noSettingsItem("bug_gem")
@JvmField
val ROCK_GEM = noSettingsItem("rock_gem")
@JvmField
val GHOST_GEM = noSettingsItem("ghost_gem")
@JvmField
val DRAGON_GEM = noSettingsItem("dragon_gem")
@JvmField
val DARK_GEM = noSettingsItem("dark_gem")
@JvmField
val STEEL_GEM = noSettingsItem("steel_gem")
@JvmField
val FAIRY_GEM = noSettingsItem("fairy_gem")
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Settings()))
@@ -82,9 +82,12 @@ import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPa
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
@@ -132,6 +135,7 @@ import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
@@ -167,6 +171,7 @@ import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.FleeBattlePacketHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
@@ -248,6 +253,7 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(PokemonStateUpdatePacket.ID, PokemonStateUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TetheringUpdatePacket.ID, TetheringUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
// Evolution start
@@ -314,6 +320,9 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
this.createClientBound(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(GlobalSpeciesFeatureSyncPacket.ID, GlobalSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
@@ -400,6 +409,7 @@ object CobblemonNetwork : NetworkManager {
this.createServerBound(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler)
this.createServerBound(SpectateBattlePacket.ID, SpectateBattlePacket::decode, SpectateBattleHandler)
this.createServerBound(RemoveSpectatorPacket.ID, RemoveSpectatorPacket::decode, RemoveSpectatorHandler)
this.createServerBound(FleeBattlePacket.ID, FleeBattlePacket::decode, FleeBattlePacketHandler)
// Trade
this.createServerBound(AcceptTradeRequestPacket.ID, AcceptTradeRequestPacket::decode, AcceptTradeRequestHandler)
@@ -16,6 +16,7 @@ import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.sound.BlockSoundGroup
import net.minecraft.sound.SoundEvent
import net.minecraft.sound.SoundEvents
object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Registry<SoundEvent>>, SoundEvent>() {
@@ -84,6 +85,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
val MEDICINE_PILLS_USE = this.create("medicine_pills.use")
@JvmField
val MEDICINE_SPRAY_USE = this.create("medicine_spray.use")
@JvmField
val MEDICINE_FEATHER_USE = this.create("medicine_feather.use")
@JvmField
val BERRY_HARVEST = this.create("berry.harvest")
@@ -118,6 +121,14 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
@JvmField
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossilmachine.unprotected")
@JvmField
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
@JvmField
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
@JvmField
val COIN_POUCH_STEP = this.create("coin_pouch.step")
@JvmField
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
@JvmField
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
@JvmField
@@ -129,6 +140,52 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
@JvmField
val TUMBLESTONE_STEP = this.create("tumblestone.step")
@JvmField
val GIMMIGHOUL_GIVE_ITEM_SMALL = this.create("gimmighoul.give_item_small")
@JvmField
val GIMMIGHOUL_REVEAL = this.create("gimmighoul.reveal")
@JvmField
val BERRY_BUSH_BREAK = this.create("berry_bush.break")
@JvmField
val BERRY_BUSH_PLACE = this.create("berry_bush.place")
@JvmField
val BIG_ROOT_BREAK = this.create("big_root.break")
@JvmField
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
@JvmField
val MINT_BREAK = this.create("mint.break")
@JvmField
val MINT_PLACE = this.create("mint.place")
@JvmField
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
@JvmField
val MEDICINAL_LEEK_PLACE = this.create("medicinal_leek.plant")
@JvmField
val GILDED_CHEST_OPEN = this.create("gilded_chest.open")
@JvmField
val GILDED_CHEST_CLOSE = this.create("gilded_chest.close")
@JvmField
val GILDED_CHEST_STEP = this.create("gilded_chest.step")
@JvmField
val GILDED_CHEST_HIT = this.create("gilded_chest.hit")
@JvmField
val GILDED_CHEST_BREAK = this.create("gilded_chest.break")
@JvmField
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
@JvmField
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
COIN_POUCH_BREAK,
COIN_POUCH_STEP,
COIN_POUCH_PLACE,
COIN_POUCH_HIT,
COIN_POUCH_STEP
)
@JvmField
val IMPACT_NORMAL = this.create("impact.normal")
@JvmField
@@ -184,5 +241,59 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
TUMBLESTONE_STEP
)
@JvmField
val BERRY_BUSH_SOUNDS = BlockSoundGroup(1f, 1f,
BERRY_BUSH_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
BERRY_BUSH_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_STEP
)
@JvmField
val BIG_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
BIG_ROOT_BREAK,
SoundEvents.BLOCK_ROOTS_STEP,
SoundEvents.BLOCK_ROOTS_PLACE,
SoundEvents.BLOCK_ROOTS_HIT,
SoundEvents.BLOCK_ROOTS_FALL
)
@JvmField
val ENERGY_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
SoundEvents.BLOCK_ROOTS_BREAK,
SoundEvents.BLOCK_ROOTS_STEP,
ENERGY_ROOT_PLACE,
SoundEvents.BLOCK_ROOTS_HIT,
SoundEvents.BLOCK_ROOTS_FALL
)
@JvmField
val MEDICINAL_LEEK_SOUNDS = BlockSoundGroup(1f, 1f,
MEDICINAL_LEEK_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MEDICINAL_LEEK_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
MINT_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MINT_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
GILDED_CHEST_BREAK,
GILDED_CHEST_STEP,
GILDED_CHEST_PLACE,
GILDED_CHEST_HIT,
GILDED_CHEST_STEP
)
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.entity.LivingEntity
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
@@ -88,6 +89,8 @@ class DropTable {
amount: IntRange = this.amount
) {
val drops = getDrops(amount).toMutableList()
val heldItem = (entity as PokemonEntity).pokemon.heldItemNoCopy()
if (!heldItem.isEmpty) entity.dropItem(heldItem.item)
LOOT_DROPPED.postThen(
event = LootDroppedEvent(this, player, entity, drops),
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
@@ -33,6 +33,7 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEv
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
@@ -66,6 +67,8 @@ object CobblemonEvents {
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
@JvmField
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
@JvmField
val HELD_ITEM_UPDATED = CancelableObservable<HeldItemUpdatedEvent>()
@JvmField
val THROWN_POKEBALL_HIT = CancelableObservable<ThrownPokeballHitEvent>()
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.pokemon.interaction
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.entity.LivingEntity
import net.minecraft.item.ItemStack
/**
* Event published when a held item is being updated on a [Pokemon].
* Cancelling the event will prevent any action from being taken on
* the Pokémon.
*
* [newItem] differs from [originalStack] in that the former is a
* one-sized version of the original (Pokémon cannot hold stacks) and
* changing it in any way will not affect the original item held by
* the player.
*
* @author Whatsy, Hiroku
* @since November 13th, 2023
*/
data class HeldItemUpdatedEvent(
val cause: LivingEntity?,
val pokemon: Pokemon,
val originalStack: ItemStack,
val decrement: Boolean,
val oldItem: ItemStack,
val newItem: ItemStack
) : Cancelable()
@@ -19,6 +19,7 @@ import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.world.BlockView
import net.minecraft.world.World
/**
@@ -77,6 +78,11 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
return BlockRenderType.MODEL
}
override fun getPickStack(world: BlockView, pos: BlockPos, state: BlockState): ItemStack {
val blockEntity = world.getBlockEntity(pos) as? MultiblockEntity ?: return ItemStack.EMPTY
return if (blockEntity.multiblockStructure == null) super.getPickStack(world, pos, state) else ItemStack.EMPTY
}
abstract fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity
}
@@ -34,4 +34,10 @@ interface PassiveEvolution : Evolution {
return false
}
/**
* If the evolution will disappear once the conditions are no longer met.
*/
val permanent: Boolean
}
@@ -11,10 +11,12 @@ package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.substitute
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
/**
* A [SpeciesFeatureProvider] which is a string value selected from a fixed list of choices. Parameters exist
@@ -24,15 +26,46 @@ import net.minecraft.nbt.NbtCompound
* @since November 30th, 2022
*/
open class ChoiceSpeciesFeatureProvider(
override val keys: List<String>,
override var keys: List<String>,
var default: String? = null,
var choices: List<String> = listOf(),
var isAspect: Boolean = true,
var aspectFormat: String = "{{choice}}"
) : SpeciesFeatureProvider<StringSpeciesFeature>, CustomPokemonPropertyType<StringSpeciesFeature>, AspectProvider {
override val needsKey = true
) : SynchronizedSpeciesFeatureProvider<StringSpeciesFeature>, CustomPokemonPropertyType<StringSpeciesFeature>, AspectProvider {
override var needsKey = true
override var visible = false
fun getAspect(feature: StringSpeciesFeature) = aspectFormat.substitute("choice", feature.value)
override fun encode(buffer: PacketByteBuf) {
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
buffer.writeNullable(default) { _, value -> buffer.writeString(value) }
buffer.writeCollection(choices) { _, value -> buffer.writeString(value) }
buffer.writeBoolean(isAspect)
buffer.writeString(aspectFormat)
buffer.writeBoolean(needsKey)
}
override fun decode(buffer: PacketByteBuf) {
keys = buffer.readList { buffer.readString() }
default = buffer.readNullable { buffer.readString() }
choices = buffer.readList { buffer.readString() }
isAspect = buffer.readBoolean()
aspectFormat = buffer.readString()
needsKey = buffer.readBoolean()
}
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<StringSpeciesFeature>? {
return null
}
override fun invoke(buffer: PacketByteBuf, name: String): StringSpeciesFeature? {
return if (name in keys) {
StringSpeciesFeature(name, "").also { it.decode(buffer) }
} else {
null
}
}
fun getAllAspects(): MutableList<String> {
val aspects = choices.toMutableList()
choices.forEach {
@@ -45,10 +78,10 @@ open class ChoiceSpeciesFeatureProvider(
internal constructor(): this(emptyList())
fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
override fun get(pokemon: Pokemon) = pokemon.getFeature<StringSpeciesFeature>(keys.first())
override fun invoke(pokemon: Pokemon): StringSpeciesFeature? {
val existing = pokemon.getFeature<StringSpeciesFeature>(keys.first())
val existing = get(pokemon)
return if (existing != null && existing.value in choices) {
existing
} else {
@@ -88,7 +121,7 @@ open class ChoiceSpeciesFeatureProvider(
override fun provide(pokemon: Pokemon): Set<String> {
return if (isAspect) {
pokemon.getFeature<StringSpeciesFeature>(keys.first())?.let { setOf(getAspect(it)) } ?: emptySet()
get(pokemon)?.let { setOf(getAspect(it)) } ?: emptySet()
} else {
emptySet()
}
@@ -12,10 +12,12 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import kotlin.random.Random
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
/**
* A simple [SpeciesFeature] that is a true/false flag value. It implements [CustomPokemonProperty] for use in
@@ -26,7 +28,7 @@ import net.minecraft.nbt.NbtCompound
* @author Hiroku
* @since May 13th, 2022
*/
open class FlagSpeciesFeature(override val name: String) : SpeciesFeature, CustomPokemonProperty {
open class FlagSpeciesFeature(override val name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
constructor(name: String, enabled: Boolean): this(name) {
this.enabled = enabled
}
@@ -53,6 +55,14 @@ open class FlagSpeciesFeature(override val name: String) : SpeciesFeature, Custo
return this
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeBoolean(enabled)
}
override fun decode(buffer: PacketByteBuf) {
enabled = buffer.readBoolean()
}
override fun asString() = "$name=$enabled"
override fun apply(pokemon: Pokemon) {
@@ -71,11 +81,37 @@ open class FlagSpeciesFeature(override val name: String) : SpeciesFeature, Custo
override fun matches(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(name)?.enabled == enabled
}
class FlagSpeciesFeatureProvider : SpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, AspectProvider {
override val keys: List<String>
class FlagSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<FlagSpeciesFeature>, CustomPokemonPropertyType<FlagSpeciesFeature>, AspectProvider {
override var keys: List<String> = emptyList()
// Uses get() = true because that way there's no backing field. It MUST be true, this way no JSON trickery will overwrite it
override val needsKey get() = true
var default: String? = null
val isAspect = true
var isAspect = true
override var visible: Boolean = false
override fun invoke(buffer: PacketByteBuf, name: String): FlagSpeciesFeature? {
return if (name in keys) {
FlagSpeciesFeature(name).also { it.decode(buffer) }
} else {
null
}
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
buffer.writeNullable(default) { _, value -> buffer.writeString(value) }
buffer.writeBoolean(isAspect)
}
override fun decode(buffer: PacketByteBuf) {
keys = buffer.readList { it.readString() }
default = buffer.readNullable { it.readString() }
isAspect = buffer.readBoolean()
}
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<FlagSpeciesFeature>? {
return null
}
override fun examples() = setOf("true", "false")
@@ -94,8 +130,10 @@ class FlagSpeciesFeatureProvider : SpeciesFeatureProvider<FlagSpeciesFeature>, C
constructor(vararg keys: String) : this(keys.toList())
override fun get(pokemon: Pokemon) = pokemon.getFeature<FlagSpeciesFeature>(keys.first())
override fun invoke(pokemon: Pokemon): FlagSpeciesFeature? {
return pokemon.getFeature(keys.first())
return get(pokemon)
?: when (default) {
"random" -> FlagSpeciesFeature(keys.first(), Random.Default.nextBoolean())
in setOf("true", "false") -> FlagSpeciesFeature(keys.first(), default.toBoolean())
@@ -8,13 +8,17 @@
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.SpeciesFeatureProviderAdapter
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
@@ -24,6 +28,7 @@ import net.minecraft.nbt.NbtCompound
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
/**
* A registry very similar to [SpeciesFeatures] but the [SpeciesFeatureProvider] contained within it
@@ -42,11 +47,15 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
override val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(SpeciesFeatureProvider::class.java, SpeciesFeatureProviderAdapter)
.registerTypeAdapter(Vec3d::class.java, Vec3dAdapter)
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.create()
override val typeToken: TypeToken<SpeciesFeatureProvider<*>> = TypeToken.get(SpeciesFeatureProvider::class.java)
override val resourcePath: String = "global_species_features"
override fun sync(player: ServerPlayerEntity) {}
override fun sync(player: ServerPlayerEntity) {
player.sendPacket(GlobalSpeciesFeatureSyncPacket(codeFeatures + resourceFeatures))
}
override fun reload(data: Map<Identifier, SpeciesFeatureProvider<*>>) {
resourceFeatures.keys.toList().forEach(this::unregister)
@@ -59,6 +68,10 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
codeFeatures.putAll(entries.map { it.toPair() })
}
private fun register(name: String, provider: SpeciesFeatureProvider<*>, isCoded: Boolean) {
val mapping = if (isCoded) codeFeatures else resourceFeatures
if (provider is AspectProvider) {
@@ -0,0 +1,181 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.BarSummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.JsonObject
import com.google.gson.annotations.SerializedName
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
/**
* A species feature value that's just an integer. Complex stuff.
* @author Hiroku
*/
class IntSpeciesFeature(override var name: String) : SynchronizedSpeciesFeature, CustomPokemonProperty {
var value = 0
constructor(): this("")
constructor(name: String, value: Int): this(name) {
this.value = value
}
override fun saveToNBT(pokemonNBT: NbtCompound): NbtCompound {
pokemonNBT.putInt(name, value)
return pokemonNBT
}
override fun loadFromNBT(pokemonNBT: NbtCompound): SynchronizedSpeciesFeature {
value = pokemonNBT.getInt(name)
return this
}
override fun saveToJSON(pokemonJSON: JsonObject): JsonObject {
pokemonJSON.addProperty(name, value)
return pokemonJSON
}
override fun loadFromJSON(pokemonJSON: JsonObject): SpeciesFeature {
value = pokemonJSON.get(name).asInt
return this
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeInt(value)
}
override fun decode(buffer: PacketByteBuf) {
value = buffer.readInt()
}
override fun asString() = "$name=$value"
override fun apply(pokemon: Pokemon) {
val featureProvider = SpeciesFeatures.getFeature(name) ?: return
if (featureProvider in SpeciesFeatures.getFeaturesFor(pokemon.species)) {
val existingFeature = pokemon.getFeature<IntSpeciesFeature>(name)
if (existingFeature != null) {
existingFeature.value = value
} else {
pokemon.features.add(IntSpeciesFeature(name, value))
}
pokemon.updateAspects()
}
}
override fun matches(pokemon: Pokemon) = pokemon.getFeature<IntSpeciesFeature>(name)?.value == value
}
class IntSpeciesFeatureProvider : SynchronizedSpeciesFeatureProvider<IntSpeciesFeature>, CustomPokemonPropertyType<IntSpeciesFeature> {
class DisplayData : Encodable, Decodable {
var name: String = ""
@SerializedName(value = "colour" /* fuck you we use real english */, alternate = ["color"])
var colour = Vec3d(255.0, 255.0, 255.0)
var underlay: Identifier? = null
var overlay: Identifier? = null
override fun decode(buffer: PacketByteBuf) {
name = buffer.readString()
colour = Vec3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble())
underlay = buffer.readNullable { buffer.readIdentifier() }
overlay = buffer.readNullable { buffer.readIdentifier() }
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeString(name)
buffer.writeDouble(colour.x)
buffer.writeDouble(colour.y)
buffer.writeDouble(colour.z)
buffer.writeNullable(underlay) { _, value -> buffer.writeIdentifier(value) }
buffer.writeNullable(overlay) { _, value -> buffer.writeIdentifier(value) }
}
}
override var keys = listOf<String>()
// Uses get() = true because that way there's no backing field. It MUST be true, this way no JSON trickery will overwrite it
override val needsKey get() = true
override var visible = false
var default: Int? = null
var min = 0
var max = 100
var display: DisplayData? = null
override fun fromString(value: String?) = value?.toIntOrNull()?.takeIf { it in min..max }?.let { IntSpeciesFeature(keys.first(), it) }
override fun examples() = emptyList<String>()
override fun invoke(buffer: PacketByteBuf, name: String): IntSpeciesFeature? {
return if (name in keys) {
IntSpeciesFeature(name, buffer.readInt())
} else {
null
}
}
override fun invoke(pokemon: Pokemon): IntSpeciesFeature? {
return get(pokemon) ?: default?.let { IntSpeciesFeature(keys.first(), it) }
}
override fun invoke(nbt: NbtCompound): IntSpeciesFeature? {
return if (nbt.contains(keys.first())) {
IntSpeciesFeature(keys.first(), nbt.getInt(keys.first()))
} else {
null
}
}
override fun invoke(json: JsonObject): IntSpeciesFeature? {
return if (json.has(keys.first())) {
IntSpeciesFeature(keys.first(), json.get(keys.first()).asInt)
} else {
null
}
}
override fun get(pokemon: Pokemon) = pokemon.features.filterIsInstance<IntSpeciesFeature>().find { it.name in keys }
override fun encode(buffer: PacketByteBuf) {
buffer.writeCollection(keys) { _, value -> buffer.writeString(value) }
buffer.writeNullable(default) { _, value -> buffer.writeInt(value) }
buffer.writeInt(min)
buffer.writeInt(max)
buffer.writeNullable(display) { _, value -> value.encode(buffer) }
}
override fun decode(buffer: PacketByteBuf) {
keys = buffer.readList { buffer.readString() }
default = buffer.readNullable { buffer.readInt() }
min = buffer.readInt()
max = buffer.readInt()
display = buffer.readNullable { DisplayData().also { it.decode(buffer) } }
}
override fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<IntSpeciesFeature>? {
return display?.let {
BarSummarySpeciesFeatureRenderer(
name = keys.first(),
displayName = it.name.asTranslated(),
min = min,
max = max,
colour = it.colour,
underlay = it.underlay ?: cobblemonResource("textures/gui/summary/summary_stats_other_bar.png"),
overlay = it.overlay ?: cobblemonResource("textures/gui/summary/summary_stats_generic_overlay.png"),
pokemon = pokemon
)
}
}
}
@@ -8,10 +8,13 @@
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
@@ -38,17 +41,24 @@ object SpeciesFeatureAssignments : JsonDataRegistry<SpeciesFeatureAssignment> {
override val typeToken = TypeToken.get(SpeciesFeatureAssignment::class.java)
override val resourcePath = "species_feature_assignments"
private val assignments = mutableMapOf<String, MutableSet<String>>()
private val assignments = mutableMapOf<Identifier, MutableSet<String>>()
override fun sync(player: ServerPlayerEntity) {}
override fun sync(player: ServerPlayerEntity) {
player.sendPacket(SpeciesFeatureAssignmentSyncPacket(assignments))
}
override fun reload(data: Map<Identifier, SpeciesFeatureAssignment>) {
data.values.forEach {
it.pokemon.forEach { pokemon ->
assignments.getOrPut(pokemon) { mutableSetOf() }.addAll(it.features)
assignments.getOrPut(pokemon.asIdentifierDefaultingNamespace()) { mutableSetOf() }.addAll(it.features)
}
}
this.observable.emit(this)
}
fun getFeatures(species: Species) = assignments[species.showdownId()] ?: emptySet()
fun loadOnClient(data: Map<Identifier, MutableSet<String>>) {
this.assignments.clear()
this.assignments.putAll(data)
}
fun getFeatures(species: Species) = assignments[species.resourceIdentifier] ?: emptySet()
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
/**
* A provider of [SpeciesFeature]s. These must be registered via [SpeciesFeatures] either programmatically or
@@ -8,13 +8,17 @@
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.SpeciesFeatureProviderAdapter
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
@@ -22,6 +26,7 @@ import com.google.gson.reflect.TypeToken
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
/**
* A registry for [SpeciesFeatureProvider]s. This is the backbone of species-specific data such as
@@ -48,11 +53,15 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
override val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(SpeciesFeatureProvider::class.java, SpeciesFeatureProviderAdapter)
.registerTypeAdapter(Vec3d::class.java, Vec3dAdapter)
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.create()
override val typeToken: TypeToken<SpeciesFeatureProvider<*>> = TypeToken.get(SpeciesFeatureProvider::class.java)
override val resourcePath: String = "species_features"
override fun sync(player: ServerPlayerEntity) {}
override fun sync(player: ServerPlayerEntity) {
player.sendPacket(StandardSpeciesFeatureSyncPacket(codeFeatures + resourceFeatures))
}
override fun reload(data: Map<Identifier, SpeciesFeatureProvider<*>>) {
resourceFeatures.keys.toList().forEach(this::unregister)
@@ -62,6 +71,9 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
fun getCodeFeature(name: String) = resourceFeatures[name]
fun getResourceFeature(name: String) = codeFeatures[name]
fun getFeature(name: String) = getCodeFeature(name) ?: getResourceFeature(name)
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
codeFeatures.putAll(entries.map { it.toPair() })
}
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
fun getFeaturesFor(species: Species): List<SpeciesFeatureProvider<*>> {
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
/**
* A species feature value that is a string value.
@@ -22,7 +23,7 @@ import net.minecraft.nbt.NbtCompound
class StringSpeciesFeature(
override val name: String,
var value: String
) : SpeciesFeature, CustomPokemonProperty {
) : SynchronizedSpeciesFeature, CustomPokemonProperty {
override fun saveToNBT(pokemonNBT: NbtCompound): NbtCompound {
pokemonNBT.putString(name, value)
return pokemonNBT
@@ -43,6 +44,14 @@ class StringSpeciesFeature(
return this
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeString(value)
}
override fun decode(buffer: PacketByteBuf) {
value = buffer.readString()
}
override fun asString() = "$name=$value"
override fun apply(pokemon: Pokemon) {
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
/**
* A species feature that can be synchronized to the client. These must be managed by a [SynchronizedSpeciesFeatureProvider].
*
* @author Hiroku
* @since November 13th, 2023
*/
interface SynchronizedSpeciesFeature : SpeciesFeature, Encodable, Decodable
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokemon.feature
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.SummarySpeciesFeatureRenderer
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.network.PacketByteBuf
/**
* A species feature provider that will be synchronized to the client. For it to be renderable in the summary
* screen of a Pokémon it must also provide a [SummarySpeciesFeatureRenderer] in [getRenderer]. Note that you
* really don't want to initialize a renderer outside of that function call because if the server ever initializes
* it then you're going to get crashes on dedicated servers (this is a bad thing).
*
* @author Hiroku
* @since November 13th, 2023
*/
interface SynchronizedSpeciesFeatureProvider<T : SynchronizedSpeciesFeature> : SpeciesFeatureProvider<T>, Encodable, Decodable {
var visible: Boolean
operator fun invoke(buffer: PacketByteBuf, name: String): T?
/** Gets the feature from this Pokémon, if it has been created yet. */
fun get(pokemon: Pokemon): T?
/** Only run this from the client. */
fun getRenderer(pokemon: Pokemon): SummarySpeciesFeatureRenderer<T>?
}
@@ -29,7 +29,7 @@ import net.minecraft.util.math.Vec3d
* @since January 4th, 2023
*/
class BedrockParticle(
var texture: Identifier = Identifier("minecraft:textures/particle/bubble.png"),
var texture: Identifier = Identifier("minecraft:textures/particles/bubble.png"),
var material: ParticleMaterial = ParticleMaterial.ALPHA,
var uvMode: ParticleUVMode = StaticParticleUVMode(),
var sizeX: Expression = NumberExpression(0.15),
@@ -0,0 +1,51 @@
/*
* 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.spawning.influence
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import net.minecraft.registry.tag.BlockTags
/**
* Implements a [SpawningInfluence] that prevents Pokémon spawning on certain blocks.
* This ensures that Pokémon don't spawn in areas that could disrupt player-built structures or mechanisms.
* The influence checks the block directly above the potential spawn location; if the block is in the restricted list,
* the spawn is disallowed.
*
* @author Aethen
* @since February 20th, 2024
*/
open class RestrictedSpawnBlocksInfluence
: SpawningInfluence {
// The list of blocks that Pokémon are not allowed to spawn on.
private val restrictedBlocks = BlockTags.RAILS
/**
* Affects the spawnable status of a Pokémon spawn detail.
* If the block directly above the spawn location is in the restricted list, the spawn is disallowed.
*
* @param detail The Pokémon spawn detail to be affected.
* @param ctx The context of the spawning event.
* @return `true` if the spawn is allowed, `false` if it is disallowed.
*/
override fun affectSpawnable(detail: SpawnDetail, ctx: SpawningContext): Boolean {
// If the spawn detail is not a Pokémon, it is not affected by this influence.
if (detail.type != "pokemon") return true
// Get the position of the potential spawn location.
val pokemonSpawnPos = ctx.position
// Examine the block immediately above the spawn block to check for a rail
// Potentially need a refactor if we ever want to check the spawn block itself.
return ctx.world.getBlockState(pokemonSpawnPos.withY(pokemonSpawnPos.y + 1)).isIn(restrictedBlocks).not()
}
}
@@ -13,8 +13,10 @@ import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
import com.cobblemon.mod.common.api.spawning.SpawnerManager
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
import com.cobblemon.mod.common.api.spawning.influence.RestrictedSpawnBlocksInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
import com.cobblemon.mod.common.util.mutableLazy
import net.minecraft.server.network.ServerPlayerEntity
/**
@@ -26,14 +28,31 @@ import net.minecraft.server.network.ServerPlayerEntity
* @since February 14th, 2022
*/
object PlayerSpawnerFactory {
var spawns: SpawnPool = CobblemonSpawnPools.WORLD_SPAWN_POOL
var influenceBuilders = mutableListOf<(player: ServerPlayerEntity) -> SpawningInfluence?>({ PlayerLevelRangeInfluence(it, variation = 5) })
var spawns: SpawnPool by mutableLazy {
CobblemonSpawnPools.WORLD_SPAWN_POOL
}
/**
* The list of influences for a new [PlayerSpawner].
* The influences will be added to the spawner in the order they are added to this list.
*
* [PlayerLevelRangeInfluence] adjusts the level range of Pokémon that can spawn based on the player's level.
* [RestrictedSpawnBlocksInfluence] prevents Pokémon from spawning on certain blocks.
*/
var influenceBuilders = mutableListOf<(player: ServerPlayerEntity) -> SpawningInfluence?>({
PlayerLevelRangeInfluence(
it,
variation = 5
)
}, { RestrictedSpawnBlocksInfluence() })
fun create(spawnerManager: SpawnerManager, player: ServerPlayerEntity): PlayerSpawner {
val influences = influenceBuilders.mapNotNull { it(player) }
return PlayerSpawner(player, spawns, spawnerManager).also {
it.influences.addAll(influences)
it.influences.addAll(CobblemonSpawnRules.rules.values.filter(SpawnRule::enabled).flatMap(SpawnRule::components))
it.influences.addAll(
CobblemonSpawnRules.rules.values.filter(SpawnRule::enabled).flatMap(SpawnRule::components)
)
}
}
}
@@ -11,12 +11,14 @@ package com.cobblemon.mod.common.api.storage.party
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.PartyCheckContext
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.pokemon.evolution.PassiveEvolution
import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.util.*
import net.minecraft.nbt.NbtCompound
import net.minecraft.server.network.ServerPlayerEntity
@@ -123,6 +125,12 @@ open class PlayerPartyStore(
// Passive evolutions
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
val removeList = mutableListOf<Evolution>()
pokemon.evolutionProxy.server().forEach {
if (!it.test(pokemon) && it is LevelUpEvolution && !it.permanent)
removeList.add(it)
}
removeList.forEach { pokemon.evolutionProxy.server().remove(it) }
}
// Friendship
// ToDo expand this down the line just a very basic implementation for the first releases
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
import com.cobblemon.mod.common.util.battleLang
@@ -70,18 +71,26 @@ class DamageInstruction(
}
battle.dispatch {
if (!causedFaint) {
val pokemonEntity = battlePokemon.entity
if (!causedFaint && pokemonEntity != null) {
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
pkt.sendToPlayersAround(
x = pokemonEntity.x,
y = pokemonEntity.y,
z = pokemonEntity.z,
worldKey = pokemonEntity.world.registryKey,
distance = 50.0
)
}
battlePokemon.entity?.let { pokemonEntity ->
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
pkt.sendToPlayersAround(
x = pokemonEntity.x,
y = pokemonEntity.y,
z = pokemonEntity.z,
worldKey = pokemonEntity.world.registryKey,
distance = 50.0
)
}
if (pokemonEntity != null) {
RunPosableMoLangPacket(pokemonEntity.id, setOf("q.particle('cobblemon:hit', 'target')")).sendToPlayersAround(
x = pokemonEntity.x,
y = pokemonEntity.y,
z = pokemonEntity.z,
worldKey = pokemonEntity.world.registryKey,
distance = 50.0
)
}
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import net.minecraft.block.*
import net.minecraft.item.ItemPlacementContext
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.WorldAccess
class CoinPouchBlock(settings: Settings, val small: Boolean) : HorizontalFacingBlock(settings) {
init {
this.defaultState = this.stateManager.defaultState
.with(NATURAL, false)
.with(FACING, Direction.NORTH)
}
override fun getOutlineShape(
state: BlockState?,
world: BlockView?,
pos: BlockPos?,
context: ShapeContext?
) = if (!small) super.getOutlineShape(state, world, pos, context) else {
VoxelShapes.cuboid(0.3125, 0.0, 0.3125, 0.6875, 0.3125, 0.6875)
}
override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
var blockState = defaultState
val worldView = ctx.world
val blockPos = ctx.blockPos
ctx.placementDirections.forEach { direction ->
if (direction.axis.isHorizontal) {
blockState = blockState.with(FACING, direction.opposite) as BlockState
if (blockState.canPlaceAt(worldView, blockPos)) {
return blockState
}
}
}
return null
}
@Deprecated("Deprecated in Java")
override fun getStateForNeighborUpdate(
state: BlockState,
direction: Direction,
neighborState: BlockState,
world: WorldAccess,
pos: BlockPos,
neighborPos: BlockPos
): BlockState {
return if (direction == state.get(FACING) && !state.canPlaceAt(world, pos)) Blocks.AIR.defaultState
else super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(FACING, NATURAL)
}
companion object {
val NATURAL: BooleanProperty = BooleanProperty.of("natural")
}
}
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
import net.minecraft.block.*
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemPlacementContext
@@ -216,6 +217,11 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
override fun asString() = label
}
@Deprecated("Deprecated in Java")
override fun canPathfindThrough(state: BlockState?, world: BlockView?, pos: BlockPos?, type: NavigationType?): Boolean {
return false
}
companion object {
val PART = EnumProperty.of("part", TankPart::class.java)
val TRIGGERED = Properties.TRIGGERED
@@ -0,0 +1,228 @@
/*
* 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.chest
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.scheduling.afterOnServer
import com.cobblemon.mod.common.block.entity.GildedChestBlockEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType
import net.minecraft.block.BlockState
import net.minecraft.block.BlockWithEntity
import net.minecraft.block.Blocks
import net.minecraft.block.HorizontalFacingBlock
import net.minecraft.block.ShapeContext
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.mob.PiglinBrain
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemPlacementContext
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundCategory
import net.minecraft.state.StateManager
import net.minecraft.state.property.Properties
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.ActionResult
import net.minecraft.util.BlockMirror
import net.minecraft.util.BlockRotation
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
import net.minecraft.util.ItemScatterer
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.World
@Suppress("OVERRIDE_DEPRECATION")
class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWithEntity(settings) {
init {
defaultState = defaultState.with(Properties.HORIZONTAL_FACING, Direction.SOUTH)
}
companion object {
val POKEMON_ARGS = "gimmighoul"
val LEVEL_RANGE = 5..30
val SOUTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.25, 1.0, 1.0, 0.9375)
)
val NORTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.0625, 1.0, 1.0, 0.75)
)
val WEST_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0625, 0.0, 0.0, 0.75, 1.0, 1.0)
)
val EAST_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.25, 0.0, 0.0, 0.9375, 1.0, 1.0)
)
}
override fun createBlockEntity(pos: BlockPos, state: BlockState) = GildedChestBlockEntity(pos, state, type)
override fun getOutlineShape(
state: BlockState,
world: BlockView,
pos: BlockPos,
context: ShapeContext
): VoxelShape {
return when (state.get(HorizontalFacingBlock.FACING)) {
Direction.NORTH -> NORTH_OUTLINE
Direction.SOUTH -> SOUTH_OUTLINE
Direction.WEST -> WEST_OUTLINE
else -> EAST_OUTLINE
}
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
super.appendProperties(builder)
builder.add(Properties.HORIZONTAL_FACING)
}
private val facingToYaw: HashMap<Direction, Float> = hashMapOf(
Direction.NORTH to -179.0F,
Direction.WEST to 90.0F,
Direction.SOUTH to 0.0F,
Direction.EAST to -90.0F
)
override fun getName(): MutableText {
return if (isFake()) Text.translatable("block.cobblemon.gilded_chest") else super.getName()
}
fun isFake() = (type == Type.FAKE)
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
if (isFake()) {
if (player is ServerPlayerEntity) {
spawnPokemon(world, pos, state, player)
}
world.setBlockState(pos, Blocks.AIR.defaultState)
} else super.onBreak(world, pos, state, player)
}
private fun spawnPokemon(world: World, pos: BlockPos, state: BlockState, player: ServerPlayerEntity) : ActionResult {
val properties = "$POKEMON_ARGS lvl=${LEVEL_RANGE.random()}"
val pokemon = PokemonProperties.parse(properties)
val entity = pokemon.createEntity(world)
// The yaw based on the block's facing direction
val yaw = facingToYaw[state[HorizontalFacingBlock.FACING]] ?: 0.0F
entity.dataTracker.set(PokemonEntity.SPAWN_DIRECTION, facingToYaw[state[HorizontalFacingBlock.FACING]])
val offsetDir = state[HorizontalFacingBlock.FACING]
val vec = pos.toVec3d().add(offsetDir.offsetX * 0.1 + 0.5, 0.0, offsetDir.offsetZ * 0.1 + 0.5)
entity.refreshPositionAndAngles(vec.x, vec.y, vec.z, yaw, entity.pitch)
world.spawnEntity(entity)
world.removeBlock(pos, false)
afterOnServer(ticks = 2) {
if (player !in player.world.players) {
return@afterOnServer
}
val party = player.party()
if (!player.isCreative) {
entity.forceBattle(player)
} else {
world.playSound(null, pos, CobblemonSounds.GIMMIGHOUL_REVEAL, SoundCategory.NEUTRAL)
}
}
return ActionResult.SUCCESS
}
override fun onUse(
state: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
hand: Hand,
hit: BlockHitResult
): ActionResult {
if (isFake()) {
if (player is ServerPlayerEntity) {
return spawnPokemon(world, pos, state, player)
} else {
return ActionResult.SUCCESS
}
}
val entity = world.getBlockEntity(pos) as? GildedChestBlockEntity ?: return ActionResult.FAIL
if (world.getBlockState(pos.up()).isSolidBlock(world, pos.up())) return ActionResult.FAIL
player.openHandledScreen(entity)
if (!player.world.isClient) {
PiglinBrain.onGuardedBlockInteracted(player, true)
}
val state = entity.poseableState
state.currentModel?.let {
it.moveToPose(null, state, it.getPose("OPEN")!!)
}
return ActionResult.SUCCESS
}
override fun onStateReplaced(
state: BlockState,
world: World,
pos: BlockPos,
newState: BlockState,
moved: Boolean
) {
if (!state.isOf(newState.block)) {
val chest = world.getBlockEntity(pos) as GildedChestBlockEntity
ItemScatterer.spawn(world, pos, chest.inventoryContents)
}
}
override fun getRenderType(state: BlockState?) = BlockRenderType.ENTITYBLOCK_ANIMATED
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
// val abovePosition = blockPlaceContext.blockPos.up()
// val world = blockPlaceContext.world
// if (world.getBlockState(abovePosition).canReplace(blockPlaceContext) && !world.isOutOfHeightLimit(abovePosition)) {
return defaultState.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing.opposite)
// }
// return null
}
@Deprecated("Deprecated in Java")
override fun rotate(state: BlockState, rotation: BlockRotation): BlockState {
return state.with(
Properties.HORIZONTAL_FACING, rotation.rotate(
state.get(Properties.HORIZONTAL_FACING) as Direction
)
) as BlockState
}
override fun mirror(state: BlockState, mirror: BlockMirror): BlockState {
return state.rotate(mirror.getRotation(state.get(Properties.HORIZONTAL_FACING) as Direction))
}
enum class Type(val poserId: Identifier) {
RED(cobblemonResource("gilded_chest")),
BLUE(cobblemonResource("blue_gilded_chest")),
GREEN(cobblemonResource("green_gilded_chest")),
PINK(cobblemonResource("pink_gilded_chest")),
WHITE(cobblemonResource("white_gilded_chest")),
BLACK(cobblemonResource("black_gilded_chest")),
YELLOW(cobblemonResource("yellow_gilded_chest")),
FAKE(cobblemonResource("gilded_chest"))
}
@Deprecated("Deprecated in Java")
override fun canPathfindThrough(state: BlockState?, world: BlockView?, pos: BlockPos?, type: NavigationType?): Boolean {
return false
}
}
@@ -0,0 +1,27 @@
/*
* 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.chest
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import net.minecraft.entity.Entity
class GildedState : PoseableEntityState<Entity>() {
override fun getEntity() = null
init {
setPose("CLOSED")
}
override fun updatePartialTicks(partialTicks: Float) {
this.currentPartialTicks += partialTicks
}
override val schedulingTracker = SchedulingTracker()
}
@@ -0,0 +1,149 @@
/*
* 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.CobblemonSounds
import com.cobblemon.mod.common.block.chest.GildedChestBlock.Type
import com.cobblemon.mod.common.block.chest.GildedState
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.block.entity.LootableContainerBlockEntity
import net.minecraft.block.entity.ViewerCountManager
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.DoubleInventory
import net.minecraft.inventory.Inventories
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound
import net.minecraft.screen.GenericContainerScreenHandler
import net.minecraft.sound.SoundCategory
import net.minecraft.state.property.Properties
import net.minecraft.text.Text
import net.minecraft.util.collection.DefaultedList
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type = Type.RED) : LootableContainerBlockEntity(CobblemonBlockEntities.GILDED_CHEST, pos, state) {
var inventoryContents: DefaultedList<ItemStack> = DefaultedList.ofSize(NUM_SLOTS, ItemStack.EMPTY)
val poseableState: GildedState = GildedState()
private val stateManager: ViewerCountManager = object : ViewerCountManager() {
override fun onContainerOpen(world: World, pos: BlockPos, state: BlockState) {
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_OPEN)
}
override fun onContainerClose(world: World, pos: BlockPos, state: BlockState) {
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_CLOSE)
}
override fun onViewerCountUpdate(
world: World,
pos: BlockPos,
state: BlockState,
oldViewerCount: Int,
newViewerCount: Int
) {
this@GildedChestBlockEntity.onViewerCountUpdate(world, pos, state, oldViewerCount, newViewerCount)
}
override fun isPlayerViewing(player: PlayerEntity): Boolean {
if (player.currentScreenHandler is GenericContainerScreenHandler) {
val inventory = (player.currentScreenHandler as GenericContainerScreenHandler).inventory
return inventory === this@GildedChestBlockEntity || inventory is DoubleInventory && inventory.isPart(
this@GildedChestBlockEntity
)
}
return false
}
}
override fun getType(): BlockEntityType<*> = CobblemonBlockEntities.GILDED_CHEST
override fun size() = NUM_SLOTS
override fun getContainerName() = Text.translatable("block.cobblemon.gilded_chest")
override fun createScreenHandler(syncId: Int, playerInventory: PlayerInventory?) =
GenericContainerScreenHandler.createGeneric9x3(syncId, playerInventory, this);
override fun onOpen(player: PlayerEntity) {
if (!this.removed && !player.isSpectator && type != Type.FAKE) {
stateManager.openContainer(player, this.getWorld(), this.getPos(), this.cachedState)
}
}
override fun onClose(player: PlayerEntity) {
if (!this.removed && !player.isSpectator) {
stateManager.closeContainer(player, this.getWorld(), this.getPos(), this.cachedState)
}
}
override fun getInvStackList(): DefaultedList<ItemStack> = inventoryContents
override fun setInvStackList(list: DefaultedList<ItemStack>) {
inventoryContents = list
}
companion object {
val NUM_SLOTS = 27
fun playSound(world: World, pos: BlockPos, state: BlockState, sound: net.minecraft.sound.SoundEvent) {
var d = pos.x.toDouble() + 0.5
val e = pos.y.toDouble() + 0.5
var f = pos.z.toDouble() + 0.5
val direction = state.get(Properties.HORIZONTAL_FACING)
d += direction.offsetX.toDouble() * 0.5
f += direction.offsetZ.toDouble() * 0.5
world.playSound(
null,
d,
e,
f,
sound,
SoundCategory.BLOCKS,
0.5f,
world.random.nextFloat() * 0.1f + 0.9f
)
}
}
override fun onSyncedBlockEvent(type: Int, data: Int): Boolean {
if (type == 1) {
val isNowOpen = data > 0
val wasOpen = poseableState.currentPose == "OPEN"
val model = poseableState.currentModel ?: return true
if (isNowOpen && !wasOpen) {
model.moveToPose(null, poseableState, model.getPose("OPEN")!!)
} else if (!isNowOpen && wasOpen) {
model.moveToPose(null, poseableState, model.getPose("CLOSED")!!)
}
return true
}
return super.onSyncedBlockEvent(type, data)
}
fun onViewerCountUpdate(world: World, pos: BlockPos, state: BlockState, oldViewerCount: Int, newViewerCount: Int) {
val block = state.block
world.addSyncedBlockEvent(pos, block, 1, newViewerCount)
}
override fun writeNbt(nbt: NbtCompound?) {
super.writeNbt(nbt)
if (!serializeLootTable(nbt)) {
Inventories.writeNbt(nbt, inventoryContents)
}
}
override fun readNbt(nbt: NbtCompound?) {
super.readNbt(nbt)
inventoryContents= DefaultedList.ofSize(
size(), ItemStack.EMPTY
)
if (!deserializeLootTable(nbt)) {
Inventories.readNbt(nbt, inventoryContents)
}
}
}
@@ -128,7 +128,7 @@ class RestorationTankBlockEntity(
val canUtilize = stack?.let { NaturalMaterials.isNaturalMaterial(it) } == true
&& structure.organicMaterialInside < FossilMultiblockStructure.MATERIAL_TO_START
&& structure.createdPokemon == null
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return false
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return canUtilize
if(canUtilize) {
// See if there's room
for (i in items.indices ) {
@@ -328,8 +328,8 @@ class FossilMultiblockStructure (
tankBaseEntity.masterBlockPos = null
tankTopEntity.masterBlockPos = null
// Drop fossils from machine as long as the machine is not running
if (this.timeRemaining == TIME_TO_TAKE || this.timeRemaining == -1) {
// Drop fossils from machine as long as the machine is not started or near completion
if (this.timeRemaining == -1 || this.timeRemaining >= 20) {
this.fossilInventory.forEach {
val stack = ItemStack(it.item, 1)
ItemScatterer.spawn(world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), stack)
@@ -25,6 +25,7 @@ import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
@@ -32,6 +33,7 @@ import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BlockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.pokeball.PokeBallRenderer
@@ -162,6 +164,7 @@ object CobblemonClient {
this.implementation.registerBlockRenderType(
RenderLayer.getCutout(),
CobblemonBlocks.GILDED_CHEST,
CobblemonBlocks.FOSSIL_ANALYZER,
CobblemonBlocks.APRICORN_DOOR,
CobblemonBlocks.APRICORN_TRAPDOOR,
@@ -215,6 +218,7 @@ object CobblemonClient {
CobblemonBlocks.MEDIUM_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
CobblemonBlocks.GIMMIGHOUL_CHEST
)
this.createBoatModelLayers()
@@ -244,6 +248,7 @@ object CobblemonClient {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.HANGING_SIGN, ::HangingSignBlockEntityRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.FOSSIL_ANALYZER, ::FossilAnalyzerRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.RESTORATION_TANK, ::RestorationTankRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.GILDED_CHEST, ::GildedChestBlockRenderer)
}
private fun registerEntityRenderers() {
@@ -262,12 +267,13 @@ object CobblemonClient {
BedrockParticleEffectRepository.loadEffects(resourceManager)
BedrockAnimationRepository.loadAnimations(
resourceManager = resourceManager,
directories = PokemonModelRepository.animationDirectories + PokeBallModelRepository.animationDirectories + FossilModelRepository.animationDirectories
directories = PokemonModelRepository.animationDirectories + PokeBallModelRepository.animationDirectories + FossilModelRepository.animationDirectories + BlockEntityModelRepository.animationDirectories
)
PokemonModelRepository.reload(resourceManager)
PokeBallModelRepository.reload(resourceManager)
BerryModelRepository.reload(resourceManager)
FossilModelRepository.reload(resourceManager)
BlockEntityModelRepository.reload(resourceManager)
MiscModelRepository.reload(resourceManager)
LOGGER.info("Loaded assets")
}
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.SingleActionRequest
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleOptionTile
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
import com.cobblemon.mod.common.util.battleLang
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
@@ -21,7 +22,6 @@ import net.minecraft.client.gui.Selectable
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.sound.SoundManager
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.MutableText
import net.minecraft.util.Identifier
class BattleGeneralActionSelection(
@@ -61,9 +61,8 @@ class BattleGeneralActionSelection(
}
addOption(rank++, battleLang("ui.run"), BattleGUI.runResource) {
CobblemonClient.battle?.minimised = true
MinecraftClient.getInstance().player?.sendMessage(battleLang("run_prompt"), false)
playDownSound(MinecraftClient.getInstance().soundManager)
FleeBattlePacket(battle.battleId).sendToServer()
}
}
}
@@ -46,7 +46,7 @@ import net.minecraft.text.Text
* @author Qu
* @since 2022-06-18
*/
class StarterSelectionScreen private constructor(): Screen("cobblemon.ui.starter.title".asTranslated()) {
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()) {
companion object {
// Size of UI at scale 1
@@ -63,22 +63,14 @@ class StarterSelectionScreen private constructor(): Screen("cobblemon.ui.starter
private val doubleTypeBackground = cobblemonResource("textures/gui/starterselection/starterselection_type_slot2.png")
}
lateinit var categories: List<RenderableStarterCategory>
lateinit var currentCategory: RenderableStarterCategory
lateinit var modelWidget: ModelWidget
lateinit var currentPokemon: RenderablePokemon
var currentSelection = 0
lateinit var rightButton: ArrowButton
lateinit var leftButton: ArrowButton
lateinit var typeWidget: TypeWidget
lateinit var selectionButton: SelectionButton
lateinit var starterRoundaboutCenter: StarterRoundabout
lateinit var starterRoundaboutLeft: StarterRoundabout
lateinit var starterRoundaboutRight: StarterRoundabout
constructor(categories: List<RenderableStarterCategory>) : this() {
this.categories = categories
}
private var currentSelection = 0
private lateinit var currentCategory: RenderableStarterCategory
private lateinit var modelWidget: ModelWidget
private lateinit var currentPokemon: RenderablePokemon
private lateinit var typeWidget: TypeWidget
private lateinit var starterRoundaboutCenter: StarterRoundabout
private lateinit var starterRoundaboutLeft: StarterRoundabout
private lateinit var starterRoundaboutRight: StarterRoundabout
override fun init() {
super.init()
@@ -102,7 +94,7 @@ class StarterSelectionScreen private constructor(): Screen("cobblemon.ui.starter
)
)
rightButton = ArrowButton(
val rightButton = ArrowButton(
pX = x + 183, pY = y + 151,
pWidth = 9, pHeight = 14,
right = true
@@ -110,7 +102,7 @@ class StarterSelectionScreen private constructor(): Screen("cobblemon.ui.starter
right()
}
leftButton = ArrowButton(
val leftButton = ArrowButton(
pX = x + 72, pY = y + 151,
pWidth = 9, pHeight = 14,
right = false
@@ -137,7 +129,7 @@ class StarterSelectionScreen private constructor(): Screen("cobblemon.ui.starter
addDrawableChild(modelWidget)
selectionButton = SelectionButton(
val selectionButton = SelectionButton(
pX = x + 106, pY = y + 124,
pWidth = SelectionButton.BUTTON_WIDTH, pHeight = SelectionButton.BUTTON_HEIGHT
) {
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.client.gui.summary
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.moves.Move
@@ -59,7 +60,7 @@ import net.minecraft.text.Text
*
* @param selection The index the [party] will have as the base [selectedPokemon].
*/
class Summary private constructor(party: Collection<Pokemon?>, private val editable: Boolean, selection: Int): Screen(Text.translatable("cobblemon.ui.summary.title")), Schedulable {
class Summary private constructor(party: Collection<Pokemon?>, private val editable: Boolean, private val selection: Int): Screen(Text.translatable("cobblemon.ui.summary.title")), Schedulable {
companion object {
const val BASE_WIDTH = 331
@@ -106,24 +107,27 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
override val schedulingTracker = SchedulingTracker()
internal var selectedPokemon: Pokemon
internal lateinit var selectedPokemon: Pokemon
private lateinit var mainScreen: ClickableWidget
lateinit var sideScreen: Element
lateinit var modelWidget: ModelWidget
lateinit var nicknameEntryWidget: NicknameEntryWidget
private lateinit var modelWidget: ModelWidget
private lateinit var nicknameEntryWidget: NicknameEntryWidget
private val summaryTabs = mutableListOf<SummaryTab>()
private var mainScreenIndex = INFO
var sideScreenIndex = PARTY
private val party = ArrayList(party)
init {
/**
* Initializes the Summary Screen
*/
override fun init() {
super.init()
if (this.party.isEmpty()) {
throw IllegalArgumentException("Summary UI cannot display zero Pokemon")
}
if (this.party.size > 6) {
throw IllegalArgumentException("Summary UI cannot display more than six Pokemon")
}
val idealSelected = this.party[selection]
if (idealSelected == null) {
this.selectedPokemon = this.party.first { it != null }!!
@@ -131,14 +135,6 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
this.selectedPokemon = idealSelected
}
this.listenToMoveSet()
}
/**
* Initializes the Summary Screen
*/
public override fun init() {
clearChildren()
super.init()
val x = (width - BASE_WIDTH) / 2
val y = (height - BASE_HEIGHT) / 2
@@ -245,6 +241,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
rotationY = 325F,
offsetY = -10.0
)
addDrawable(this.modelWidget)
}
fun swapPartySlot(sourceIndex: Int, targetIndex: Int) {
@@ -281,8 +278,12 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
listenToMoveSet()
displayMainScreen(mainScreenIndex)
children().find { it is EvolutionSelectScreen }?.let(this::remove)
modelWidget.pokemon = selectedPokemon.asRenderablePokemon()
nicknameEntryWidget.setSelectedPokemon(selectedPokemon)
if (this::modelWidget.isInitialized) {
this.modelWidget.pokemon = selectedPokemon.asRenderablePokemon()
}
if (this::nicknameEntryWidget.isInitialized) {
this.nicknameEntryWidget.setSelectedPokemon(selectedPokemon)
}
}
private var moveSetSubscription: ObservableSubscription<MoveSet>? = null
@@ -309,7 +310,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
*/
private fun displayMainScreen(screen: Int) {
// Get stat tab index if currently displaying stat screen
var subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
val subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
mainScreenIndex = screen
if (::mainScreen.isInitialized) remove(mainScreen)
@@ -408,10 +409,10 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
}
}
override fun render(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
renderBackground(context)
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
//this.renderBackground(context)
schedulingTracker.update(pPartialTicks / 20F)
schedulingTracker.update(delta / 20F)
val x = (width - BASE_WIDTH) / 2
val y = (height - BASE_HEIGHT) / 2
@@ -427,7 +428,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
height = PORTRAIT_SIZE
)
modelWidget.render(context, pMouseX, pMouseY, pPartialTicks)
//modelWidget.render(context, pMouseX, pMouseY, pPartialTicks)
// Render Base Resource
blitk(
@@ -576,29 +577,29 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
)
// Render all added Widgets
super.render(context, pMouseX, pMouseY, pPartialTicks)
super.render(context, mouseX, mouseY, delta)
// Render Item Tooltip
if (!heldItem.isEmpty) {
val itemHovered = pMouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && pMouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
if (itemHovered) context.drawItemTooltip(MinecraftClient.getInstance().textRenderer, heldItem, pMouseX, pMouseY)
val itemHovered = mouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && mouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
if (itemHovered) context.drawItemTooltip(MinecraftClient.getInstance().textRenderer, heldItem, mouseX, mouseY)
}
}
/**
* Whether this Screen should pause the Game in SinglePlayer
*/
override fun shouldPause(): Boolean {
return false
}
override fun shouldPause(): Boolean = false
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double): Boolean {
return children().any { it.mouseScrolled(mouseX, mouseY, amount) }
}
/*
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
return children().any { it.mouseClicked(mouseX, mouseY, button) }
}
*/
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
if (sideScreenIndex == MOVE_SWAP || sideScreenIndex == EVOLVE) sideScreen.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
@@ -606,17 +607,17 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
}
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
if ((keyCode == InputUtil.GLFW_KEY_ENTER || keyCode == InputUtil.GLFW_KEY_KP_ENTER) && nicknameEntryWidget.isFocused) { // Enter pressed
nicknameEntryWidget.isFocused = false
if ((keyCode == InputUtil.GLFW_KEY_ENTER || keyCode == InputUtil.GLFW_KEY_KP_ENTER)
&& this::nicknameEntryWidget.isInitialized
&& this.nicknameEntryWidget.isFocused
) {
this.focused = null
}
return nicknameEntryWidget.keyPressed(keyCode, scanCode, modifiers) || super.keyPressed(keyCode, scanCode, modifiers)
}
override fun charTyped(chr: Char, modifiers: Int): Boolean {
return nicknameEntryWidget.charTyped(chr, modifiers) || super.charTyped(chr, modifiers)
return super.keyPressed(keyCode, scanCode, modifiers)
}
fun playSound(soundEvent: SoundEvent) {
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, 1.0F))
}
}
@@ -19,6 +19,7 @@ import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.sound.SoundManager
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
class SummaryButton(
@@ -27,7 +28,7 @@ class SummaryButton(
val buttonWidth: Number,
val buttonHeight: Number,
val clickAction: PressAction,
private val text: MutableText? = null,
private val text: MutableText = Text.empty(),
private val resource: Identifier,
private val activeResource: Identifier? = null,
private val renderRequirement: ((button: SummaryButton) -> Boolean) = { true },
@@ -68,18 +69,16 @@ class SummaryButton(
)
// Render Text
if (text != null) {
drawScaledText(
context = context,
font = if (largeText) CobblemonResources.DEFAULT_LARGE else null,
text = if (boldText) text.bold() else text,
x = buttonX + (buttonWidth.toFloat() / 2),
y = buttonY + (buttonHeight.toFloat() / 2) - ((TEXT_HEIGHT / 2) * textScale),
scale = textScale,
centered = true,
shadow = true
)
}
drawScaledText(
context = context,
font = if (largeText) CobblemonResources.DEFAULT_LARGE else null,
text = if (boldText) text.bold() else text,
x = buttonX + (buttonWidth.toFloat() / 2),
y = buttonY + (buttonHeight.toFloat() / 2) - ((TEXT_HEIGHT / 2) * textScale),
scale = textScale,
centered = true,
shadow = true
)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
@@ -0,0 +1,110 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.summary.featurerenderers
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeature
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.client.gui.DrawContext
import net.minecraft.text.MutableText
import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.Vec3d
/**
* Renders an [IntSpeciesFeature] as a bar in the summary screen.
*
* @author Hiroku
* @since November 13th, 2023
*/
class BarSummarySpeciesFeatureRenderer(
override val name: String,
val displayName: MutableText,
val min: Int,
val max: Int,
val colour: Vec3d,
val underlay: Identifier,
val overlay: Identifier,
val pokemon: Pokemon
) : SummarySpeciesFeatureRenderer<IntSpeciesFeature> {
override fun render(drawContext: DrawContext, x: Float, y: Float, pokemon: Pokemon, feature: IntSpeciesFeature) {
val value = feature.value
val barRatio = (value - min) / (max - min).toFloat()
val barWidth = MathHelper.ceil(barRatio * 108)
blitk(
matrixStack = drawContext.matrices,
texture = underlay,
x = x,
y = y,
height = 28,
width = 124
)
val red = colour.x / 255F
val green = colour.y / 255F
val blue = colour.z / 255F
blitk(
matrixStack = drawContext.matrices,
texture = CobblemonResources.WHITE,
x = x + 8,
y = y + 16,
height = 10,
width = barWidth,
red = red,
green = green,
blue = blue
)
blitk(
matrixStack = drawContext.matrices,
texture = overlay,
x = x / StatWidget.SCALE,
y = (y + 16) / StatWidget.SCALE,
height = 20,
width = 248,
scale = StatWidget.SCALE
)
// Label
drawScaledText(
context = drawContext,
font = CobblemonResources.DEFAULT_LARGE,
text = displayName.bold(),
x = x + 62,
y = y + 2.5,
centered = true,
shadow = true
)
drawScaledText(
context = drawContext,
text = value.toString().text(),
x = x + 11,
y = y + 6,
scale = StatWidget.SCALE,
centered = true
)
drawScaledText(
context = drawContext,
text = "${MathHelper.floor(barRatio * 100)}%".text(),
x = x + 113,
y = y + 6,
scale = StatWidget.SCALE,
centered = true
)
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.summary.featurerenderers
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.client.gui.DrawContext
/**
* A renderer for some kind of [SynchronizedSpeciesFeature] so that it will display
* in the summary screen of the Pokémon (under other stats).
*
* @author Hiroku
* @since November 13th, 2023
*/
interface SummarySpeciesFeatureRenderer<T : SynchronizedSpeciesFeature> {
/** The name of the feature (so we know where to look to find it in the [Pokemon]) */
val name: String
/** Draws it at a particular position. */
fun render(drawContext: DrawContext, x: Float, y: Float, pokemon: Pokemon, feature: T)
fun render(drawContext: DrawContext, x: Float, y: Float, pokemon: Pokemon): Boolean {
val feature = pokemon.getFeature<T>(name) ?: return false
render(drawContext, x, y, pokemon, feature)
return true
}
}
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.client.gui.summary.widgets
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.gui.summary.Summary
@@ -23,15 +22,14 @@ import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import org.joml.Quaternionf
import org.joml.Vector3f
class PartySlotWidget(
private val pX: Number,
private val pY: Number,
pX: Number,
pY: Number,
private val partyWidget: PartyWidget,
private val summary: Summary,
private val pokemon: Pokemon?,
@@ -1,20 +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.gui.summary.widgets
import com.cobblemon.mod.common.util.cobblemonResource
class TypeDisplayWidget {
companion object {
private val TYPES_RESOURCE = cobblemonResource("textures/gui/types.png")
}
}
@@ -26,9 +26,7 @@ class InfoBlockWidget(
private val font: Identifier,
) : SoundlessWidget(pX, pY, blockWidth, blockHeight, Text.literal("InfoBlockWidget")) {
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
drawScaledText(
context = context,
font = font,
@@ -15,14 +15,13 @@ import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.sound.SoundManager
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.Text
class ReorderMoveButton(
val pX: Int, val pY: Int,
private val isUp: Boolean,
onPress: PressAction
): ButtonWidget((pX - OFFSET_X).toInt(), (pY + (if (isUp) OFFSET_Y_UP else OFFSET_Y_DOWN)), (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.literal(""), onPress, DEFAULT_NARRATION_SUPPLIER) {
): ButtonWidget((pX - OFFSET_X).toInt(), (pY + (if (isUp) OFFSET_Y_UP else OFFSET_Y_DOWN)), (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.empty(), onPress, DEFAULT_NARRATION_SUPPLIER) {
companion object {
private const val WIDTH = 8
@@ -29,7 +29,7 @@ class SwapMoveButton(
var move: MoveTemplate,
var movesWidget: MovesWidget,
onPress: PressAction
): ButtonWidget((pX + OFFSET_X).toInt(), (pY + OFFSET_Y).toInt(), (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.literal(""), onPress, DEFAULT_NARRATION_SUPPLIER) {
): ButtonWidget((pX + OFFSET_X).toInt(), (pY + OFFSET_Y).toInt(), (WIDTH * SCALE).toInt(), (HEIGHT * SCALE).toInt(), Text.empty(), onPress, DEFAULT_NARRATION_SUPPLIER) {
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean {
return false
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.text.bold
@@ -54,7 +56,7 @@ class StatWidget(
private const val WIDTH = 134
private const val HEIGHT = 148
private const val SCALE = 0.5F
const val SCALE = 0.5F
private const val WHITE = 0x00FFFFFF
private const val GREY = 0x00AAAAAA
@@ -64,6 +66,7 @@ class StatWidget(
private val statsBaseResource = cobblemonResource("textures/gui/summary/summary_stats_chart_base.png")
private val statsChartResource = cobblemonResource("textures/gui/summary/summary_stats_chart.png")
private val statsOtherBaseResource = cobblemonResource("textures/gui/summary/summary_stats_other_base.png")
private val statsOtherBarTemplate = cobblemonResource("textures/gui/summary/summary_stats_other_bar.png")
private val friendshipOverlayResource = cobblemonResource("textures/gui/summary/summary_stats_friendship_overlay.png")
private val tabMarkerResource = cobblemonResource("textures/gui/summary/summary_stats_tab_marker.png")
private val statIncreaseResource = cobblemonResource("textures/gui/summary/summary_stats_icon_increase.png")
@@ -84,6 +87,10 @@ class StatWidget(
}
var statTabIndex = tabIndex
val renderableFeatures = SpeciesFeatures
.getFeaturesFor(pokemon.species)
.filterIsInstance<SynchronizedSpeciesFeatureProvider<*>>()
.mapNotNull { it.getRenderer(pokemon) }
private fun drawTriangle(
colour: Vector3f,
@@ -178,6 +185,74 @@ class StatWidget(
// drawTriangle(colour, specialAttackPoint, centerPoint, hpPoint)
}
private fun drawFriendship(moduleX: Int, moduleY: Int, matrices: MatrixStack, context: DrawContext, friendship: Int) {
val barRatio = friendship / 255F
val barWidth = ceil(barRatio * 108)
blitk(
matrixStack = matrices,
texture = statsOtherBarTemplate,
x = moduleX,
y = moduleY,
height = 28,
width = 124
)
val red = 1
val green: Number = if (pokemon.friendship >= 160) 0.28 else 0.56
val blue: Number = if (pokemon.friendship >= 160) 0.4 else 0.64
blitk(
matrixStack = matrices,
texture = CobblemonResources.WHITE,
x = moduleX + 8,
y = moduleY + 18,
height = 8,
width = barWidth,
red = red,
green = green,
blue = blue
)
blitk(
matrixStack = matrices,
texture = friendshipOverlayResource,
x = moduleX / SCALE,
y = (moduleY + 16) / SCALE,
height = 20,
width = 248,
scale = SCALE
)
// Label
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = lang("ui.stats.friendship").bold(),
x = moduleX + 62,
y = moduleY + 2.5,
centered = true,
shadow = true
)
drawScaledText(
context = context,
text = friendship.toString().text(),
x = moduleX + 11,
y = moduleY + 6,
scale = SCALE,
centered = true
)
drawScaledText(
context = context,
text = "${floor(barRatio * 100)}%".text(),
x = moduleX + 113,
y = moduleY + 6,
scale = SCALE,
centered = true
)
}
override fun renderButton(context: DrawContext, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
val renderChart = statTabIndex != OTHER
@@ -328,60 +403,28 @@ class StatWidget(
renderModifiedStatIcon(matrices, nature.decreasedStat, false)
}
} else {
// Friendship
val friendshipBarWidthMax = 108
val friendshipRatio = pokemon.friendship / 255F
val friendshipBarWidth = ceil(friendshipRatio * friendshipBarWidthMax)
blitk(
matrixStack = matrices,
texture = CobblemonResources.WHITE,
x = x + 13,
y = y + 27,
height = 8,
width = friendshipBarWidth,
red = 0.92,
green = if (pokemon.friendship >= 160) 0.28 else 0.7,
blue = if (pokemon.friendship >= 160) 0.4 else 0.28
)
var drawY = y + 11
blitk(
matrixStack = matrices,
texture = friendshipOverlayResource,
x = (x + 5) / SCALE,
y = (y + 26) / SCALE,
height = 20,
width = 248,
scale = SCALE
)
drawFriendship(x + 5, drawY, matrices, context, pokemon.friendship)
drawY += 30
// Label
drawScaledText(
context = context,
font = CobblemonResources.DEFAULT_LARGE,
text = lang("ui.stats.friendship").bold(),
x = x + 67,
y = y + 12.5,
centered = true,
shadow = true
)
for (renderableFeature in renderableFeatures) {
val rendered = renderableFeature.render(
drawContext = context,
x = x + 5F,
y = drawY.toFloat(),
pokemon = pokemon
)
drawScaledText(
context = context,
text = pokemon.friendship.toString().text(),
x = x + 16,
y = y + 16,
scale = SCALE,
centered = true
)
if (rendered) {
drawY += 30
}
}
// for (value in summaries) {
// drawBarModule(x + 5, drawY, matrices, context, value)
// }
drawScaledText(
context = context,
text = "${floor(friendshipRatio * 100)}%".text(),
x = x + 118,
y = y + 16,
scale = SCALE,
centered = true
)
}
}
@@ -0,0 +1,65 @@
/*
* 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.block
import com.cobblemon.mod.common.block.entity.GildedChestBlockEntity
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BlockEntityModelRepository
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.block.entity.BlockEntityRenderer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.state.property.Properties
import net.minecraft.util.math.RotationAxis
class GildedChestBlockRenderer(context: BlockEntityRendererFactory.Context) : BlockEntityRenderer<GildedChestBlockEntity> {
override fun render(
entity: GildedChestBlockEntity,
tickDelta: Float,
matrices: MatrixStack,
vertexConsumers: VertexConsumerProvider,
light: Int,
overlay: Int
) {
val aspects = emptySet<String>()
val state = entity.poseableState
state.updatePartialTicks(tickDelta)
val poserId = entity.type.poserId
val model = BlockEntityModelRepository.getPoser(poserId, aspects)
val texture = BlockEntityModelRepository.getTexture(poserId, aspects, state.animationSeconds)
val vertexConsumer = vertexConsumers.getBuffer(model.getLayer(texture))
model.bufferProvider = vertexConsumers
state.currentModel = model
matrices.push()
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(180f))
matrices.translate(-0.5, 0.0, 0.5)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(entity.cachedState.get(Properties.HORIZONTAL_FACING).asRotation()))
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(180f))
model.setupAnimStateful(
entity = null,
state = state,
headYaw = 0F,
headPitch = 0F,
limbSwing = 0F,
limbSwingAmount = 0F,
ageInTicks = state.animationSeconds * 20
)
model.render(matrices, vertexConsumer, light, overlay, 1.0f, 1.0f, 1.0f, 1.0f)
model.withLayerContext(vertexConsumers, state, BlockEntityModelRepository.getLayers(poserId, aspects)) {
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, 1F, 1F, 1F, 1F)
}
model.setDefault()
matrices.pop()
}
}
@@ -753,7 +753,7 @@ abstract class PoseableEntityModel<T : Entity>(
}
} else if (transition != null) {
val animation = transition(previousPose, desirablePose)
val primaryAnimation = PrimaryAnimation(animation, curve = { 1F })
val primaryAnimation = if (animation is PrimaryAnimation) animation else PrimaryAnimation(animation, curve = { 1F })
state.addPrimaryAnimation(primaryAnimation)
afterOnClient(seconds = primaryAnimation.duration) {
state.setPose(desirablePose.poseName)
@@ -0,0 +1,44 @@
/*
* 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.blockentity
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.animation.StatelessAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.ModelFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.entity.Entity
class BlockEntityModel(val root: Bone) : PoseableEntityModel<Entity>() {
val boneName: String = root.children.entries.first().key
override val rootPart = (root as ModelPart).registerChildWithAllChildren(boneName)
override val isForLivingEntityRenderer = false
var idleAnimations: Array<StatelessAnimation<Entity, out ModelFrame>> = emptyArray()
var maxScale = 1F
var yTranslation = 0F
override fun registerPoses() {
val closedPose = registerPose<ModelFrame>(poseName = "CLOSED", poseType = PoseType.NONE)
val openPose = registerPose(
poseType = PoseType.OPEN,
idleAnimations = arrayOf(bedrock("gilded_chest", "open"))
)
closedPose.transitions[openPose.poseName] = { _, _ ->
bedrockStateful("gilded_chest", "opening").andThen { _, state -> state.setPose(openPose.poseName) }
}
openPose.transitions[closedPose.poseName] = { _, _ ->
bedrockStateful("gilded_chest", "closing").andThen { _, state -> state.setPose(closedPose.poseName) }
}
}
override fun getState(entity: Entity) = throw NotImplementedError("This is not supported for the gilded chest")
}
@@ -19,7 +19,7 @@ import net.minecraft.entity.Entity
class FossilModel(root: Bone) : PoseableEntityModel<Entity>() {
override val isForLivingEntityRenderer = false
//TODO: Find a better way to fetch this bone name
//TODO: Find a better way to fetch this bone name - Update the BlockEntityModel too when you figure it out
val boneName: String = root.children.entries.first().key
override val rootPart = (root as ModelPart).registerChildWithAllChildren(boneName)
// Represents a very rough middle of the model
@@ -0,0 +1,70 @@
/*
* 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.gen9
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.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class GholdengoModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("gholdengo")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val portraitScale = 2.6F
override val portraitTranslation = Vec3d(-0.3, 1.4, 0.0)
override val profileScale = 0.65F
override val profileTranslation = Vec3d(0.0, 0.76, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("gholdengo", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gholdengo", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gholdengo", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
//bedrock("gholdengo", "ground_walk")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("gholdengo", "faint") else null
}
@@ -0,0 +1,97 @@
/*
* 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.gen9
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.asExpressionLike
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class GimmighoulChestModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("gimmighoul_chest")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(0.3, -0.7, 0.0)
override val profileScale = 0.65F
override val profileTranslation = Vec3d(0.0, 0.76, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var closed: PokemonPose
lateinit var battle: PokemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("gimmighoul_chest", "blink") }
animations["cry"] = "q.bedrock_stateful('gimmighoul_chest', 'cry')".asExpressionLike()
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
condition = { it.ownerUuid != null && !it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_chest", "ground_idle")
)
)
closed = registerPose(
poseName = "closed",
poseTypes = PoseType.STATIONARY_POSES,
quirks = arrayOf(blink),
condition = { it.ownerUuid == null && !it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_chest", "mimic")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_chest", "ground_walk")
//bedrock("gimmighoul_chest", "ground_walk")
)
)
battle = registerPose(
poseName = "battle",
poseTypes = PoseType.STATIONARY_POSES,
quirks = arrayOf(blink),
condition = { it.isBattling },
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_chest", "battle_idle"),
)
)
closed.transitions[battle.poseName] = { _, _ ->
bedrockStateful("gimmighoul_chest", "surprise").andThen { _, state -> state.setPose(battle.poseName) }
}
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("gimmighoul_chest", "faint") else null
}
@@ -0,0 +1,70 @@
/*
* 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.gen9
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.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class GimmighoulRoamingModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame, BimanualFrame {
override val rootPart = root.registerChildWithAllChildren("gimmighoul_roaming")
override val head = getPart("head")
override val leftArm = getPart("arm_left")
override val rightArm = getPart("arm_right")
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override val portraitScale = 2.5F
override val portraitTranslation = Vec3d(0.0, -1.3, 0.0)
override val profileScale = 0.7F
override val profileTranslation = Vec3d(0.0, 0.76, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("gimmighoul_roaming", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_roaming", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("gimmighoul_roaming", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
//bedrock("gimmighoul_roaming", "ground_walk")
)
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("gimmighoul_roaming", "faint") else null
}
@@ -0,0 +1,63 @@
/*
* 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.repository
import com.cobblemon.mod.common.client.render.models.blockbench.blockentity.BlockEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.JsonPokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.fromJson
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import net.minecraft.entity.Entity
/**
* This is specifically for BlockEntities where we want to do more complex animation than what Java Edition already allows
* Basically with Java Edition, we can only change the texture applied to a model, if we want to move bones around, need to
* do something else, so we use this
*/
object BlockEntityModelRepository : VaryingModelRepository<Entity, BlockEntityModel>() {
override val title = "Block Entity"
override val type = "block_entities"
override val variationDirectories: List<String> = listOf("bedrock/$type/variations", "bedrock/$type")
override val poserDirectories: List<String> = listOf("bedrock/$type/posers")
override val modelDirectories: List<String> = listOf("bedrock/$type/models")
override val animationDirectories: List<String> = listOf("bedrock/$type/animations")
override val fallback = cobblemonResource("substitute")
override val isForLivingEntityRenderer = false
private val gson = GsonBuilder().create()
override fun loadJsonPoser(json: String): (Bone) -> BlockEntityModel {
val jsonObject = gson.fromJson<JsonObject>(json)
val animations = jsonObject.getAsJsonArray("animations")
val maxScale = jsonObject.get("maxScale")?.asFloat ?: 1F
val yTranslation = jsonObject.get("yTranslation")?.asFloat ?: 0F
return { bone ->
val model = BlockEntityModel(bone)
model.maxScale = maxScale
model.yTranslation = yTranslation
// I stole all this from FossilModelRepository, so I guess I'll leave the comments here
//
// Refactor this bullshit to not mention pokemon at all, it should be common to anything using animation factories.
// Even better: move to molang functions, this is ass
model.idleAnimations = animations.mapNotNull {
val animString = it.asString
val anim = animString.substringBefore("(")
if (JsonPokemonPoseableModel.ANIMATION_FACTORIES.contains(anim)) {
return@mapNotNull JsonPokemonPoseableModel.ANIMATION_FACTORIES[anim]!!.stateless(model, animString)
} else {
null
}
}.toTypedArray()
model
}
}
override fun registerInBuiltPosers() {}
}
@@ -588,6 +588,9 @@ object PokemonModelRepository : VaryingModelRepository<PokemonEntity, PokemonPos
inbuilt("litwick", ::LitwickModel)
inbuilt("lampent", ::LampentModel)
inbuilt("chandelure", ::ChandelureModel)
inbuilt("gimmighoulroaming", ::GimmighoulRoamingModel)
inbuilt("gimmighoulchest", ::GimmighoulChestModel)
inbuilt("gholdengo", ::GholdengoModel)
inbuilt("drifloon", ::DrifloonModel)
inbuilt("drifblim", ::DrifblimModel)
}
@@ -16,35 +16,25 @@ import com.cobblemon.mod.common.client.entity.PokemonClientDelegate.Companion.BE
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate.Companion.BEAM_SHRINK_TIME
import com.cobblemon.mod.common.client.keybind.boundKey
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
import com.cobblemon.mod.common.client.render.addVertex
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
import com.cobblemon.mod.common.client.render.pokeball.PokeBallPoseableState
import com.cobblemon.mod.common.client.render.renderBeaconBeam
import com.cobblemon.mod.common.client.settings.ServerSettings
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity.Companion.SPAWN_DIRECTION
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.util.isLookingAt
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.math.DoubleRange
import com.cobblemon.mod.common.util.math.geometry.toRadians
import com.cobblemon.mod.common.util.math.remap
import com.mojang.blaze3d.systems.RenderSystem
import kotlin.math.*
import net.minecraft.client.MinecraftClient
import net.minecraft.client.font.TextRenderer
import net.minecraft.client.gl.GlUniform
import net.minecraft.client.gl.ShaderProgram
import net.minecraft.client.gl.Uniform
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.LightmapTextureManager
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.RenderPhase
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.render.*
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.MobEntityRenderer
@@ -52,7 +42,6 @@ import net.minecraft.client.render.entity.model.EntityModel
import net.minecraft.client.render.item.ItemRenderer
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.text.Text
import net.minecraft.util.Identifier
@@ -64,12 +53,6 @@ import org.joml.Math
import org.joml.Quaternionf
import org.joml.Vector3f
import org.joml.Vector4f
import kotlin.math.*
import kotlin.properties.Delegates
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sin
import kotlin.math.tan
class PokemonRenderer(
context: EntityRendererFactory.Context
@@ -128,6 +111,12 @@ class PokemonRenderer(
// progressUniform?.set((sin(entity.ticksLived/20f) + 1f)/2f)
// }
// }
if (entity.ticksLived < 10) {
entity.bodyYaw = entity.dataTracker.get(SPAWN_DIRECTION)
entity.prevBodyYaw = entity.bodyYaw
}
super.render(entity, entityYaw, partialTicks, poseMatrix, buffer, packedLight)
modelNow.green = 1F
@@ -6,7 +6,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.sound
import net.minecraft.client.MinecraftClient
@@ -26,13 +26,15 @@ class ClientParty(uuid: UUID, slots: Int) : ClientStorage<PartyPosition>(uuid),
fun get(slot: Int) = get(PartyPosition(slot))
override fun get(position: PartyPosition): Pokemon? {
if (position.slot >= slots.size) {
if (position.slot >= slots.size || position.slot == -1) {
return null
}
return slots[position.slot]
}
fun isEmpty() = (slots.size == 0)
fun getPosition(pokemonID: UUID) = slots.indexOfFirst { it?.uuid == pokemonID }
override fun getPosition(pokemon: Pokemon): PartyPosition? {
for (slotNumber in slots.indices) {
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.command
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.alias
import com.cobblemon.mod.common.util.commandLang
import com.cobblemon.mod.common.util.permission
@@ -71,6 +72,7 @@ object SpawnPokemon {
}
val pokemonEntity = properties.createEntity(world)
pokemonEntity.refreshPositionAndAngles(pos.x, pos.y, pos.z, pokemonEntity.yaw, pokemonEntity.pitch)
pokemonEntity.dataTracker.set(PokemonEntity.SPAWN_DIRECTION, pokemonEntity.random.nextFloat() * 360F)
if (world.spawnEntity(pokemonEntity)) {
return Command.SINGLE_SUCCESS
}
@@ -32,6 +32,8 @@ enum class PoseType {
PROFILE,
/** A pose for rendering in the party overlay and in minor spaces like the battle tiles. */
PORTRAIT,
/** For guilded chest */
OPEN,
/** A simple type for non-living entities or errant cases. */
NONE;
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.entity.pokemon
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.CobblemonNetwork.sendPacketToServer
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.entity.Despawner
import com.cobblemon.mod.common.api.events.CobblemonEvents
@@ -32,6 +33,7 @@ import com.cobblemon.mod.common.api.types.ElementalTypes.FIRE
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.Poseable
@@ -44,6 +46,7 @@ import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimat
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler.SEND_OUT_DURATION
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Pokemon
@@ -129,6 +132,7 @@ open class PokemonEntity(
@JvmStatic val HIDE_LABEL = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
@JvmStatic val UNBATTLEABLE = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
@JvmStatic val COUNTS_TOWARDS_SPAWN_CAP = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.BOOLEAN)
@JvmStatic val SPAWN_DIRECTION = DataTracker.registerData(PokemonEntity::class.java, TrackedDataHandlerRegistry.FLOAT)
const val BATTLE_LOCK = "battle"
@@ -232,6 +236,7 @@ open class PokemonEntity(
dataTracker.startTracking(LABEL_LEVEL, 1)
dataTracker.startTracking(HIDE_LABEL, false)
dataTracker.startTracking(UNBATTLEABLE, false)
dataTracker.startTracking(SPAWN_DIRECTION, world.random.nextFloat() * 360F)
}
override fun onTrackedDataSet(data: TrackedData<*>) {
@@ -299,6 +304,13 @@ open class PokemonEntity(
this.updateEyeHeight()
}
if (ticksLived <= 20) {
clearPositionTarget()
val spawnDirection = dataTracker.get(SPAWN_DIRECTION)
setBodyYaw(spawnDirection)
prevBodyYaw = spawnDirection
}
if (this.tethering != null && !this.tethering!!.box.contains(this.x, this.y, this.z)) {
this.tethering = null
this.pokemon.recall()
@@ -824,7 +836,7 @@ open class PokemonEntity(
player.sendMessage(lang("held_item.already_holding", this.pokemon.getDisplayName(), stack.name))
return true
}
val returned = this.pokemon.swapHeldItem(stack, !player.isCreative)
val returned = this.pokemon.swapHeldItem(stack = stack, decrement = !player.isCreative)
val text = when {
giving.isEmpty -> lang("held_item.take", returned.name, this.pokemon.getDisplayName())
returned.isEmpty -> lang("held_item.give", this.pokemon.getDisplayName(), giving.name)
@@ -1028,6 +1040,21 @@ open class PokemonEntity(
dataTracker.set(NICKNAME_VISIBLE, visible)
}
/**
* Attempts to force initiate a battle with this Pokémon.
*
* @param player The player to attempt a battle with.
* @return Whether the battle was successfully started.
*/
fun forceBattle(player: PlayerEntity): Boolean {
if (!canBattle(player)) return false
if (CobblemonClient.storage.myParty.isEmpty()) return false
val selectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot) ?: return false
if (selectedPokemon.isFainted()) return false
sendPacketToServer(BattleChallengePacket(this.id, selectedPokemon.uuid))
return true
}
/**
* In the context of a Pokémon entity this checks if the Pokémon is currently set to displaying its nickname.
*
@@ -142,10 +142,10 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.PLUME_FOSSIL)
entries.add(CobblemonItems.JAW_FOSSIL)
entries.add(CobblemonItems.SAIL_FOSSIL)
entries.add(CobblemonItems.BIRD_FOSSIL)
entries.add(CobblemonItems.FISH_FOSSIL)
entries.add(CobblemonItems.DRAKE_FOSSIL)
entries.add(CobblemonItems.DINO_FOSSIL)
entries.add(CobblemonItems.FOSSILIZED_BIRD)
entries.add(CobblemonItems.FOSSILIZED_FISH)
entries.add(CobblemonItems.FOSSILIZED_DRAKE)
entries.add(CobblemonItems.FOSSILIZED_DINO)
entries.add(CobblemonItems.TUMBLESTONE)
entries.add(CobblemonItems.BLACK_TUMBLESTONE)
@@ -179,6 +179,37 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.SUSPICIOUS_SHERD)
entries.add(CobblemonItems.AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE)
entries.add(CobblemonItems.RELIC_COIN)
entries.add(CobblemonItems.RELIC_COIN_POUCH)
entries.add(CobblemonItems.RELIC_COIN_SACK)
entries.add(CobblemonItems.GILDED_CHEST)
entries.add(CobblemonItems.YELLOW_GILDED_CHEST)
entries.add(CobblemonItems.GREEN_GILDED_CHEST)
entries.add(CobblemonItems.BLUE_GILDED_CHEST)
entries.add(CobblemonItems.PINK_GILDED_CHEST)
entries.add(CobblemonItems.BLACK_GILDED_CHEST)
entries.add(CobblemonItems.WHITE_GILDED_CHEST)
entries.add(CobblemonItems.GIMMIGHOUL_CHEST)
entries.add(CobblemonItems.NORMAL_GEM)
entries.add(CobblemonItems.FIRE_GEM)
entries.add(CobblemonItems.WATER_GEM)
entries.add(CobblemonItems.GRASS_GEM)
entries.add(CobblemonItems.ELECTRIC_GEM)
entries.add(CobblemonItems.ICE_GEM)
entries.add(CobblemonItems.FIGHTING_GEM)
entries.add(CobblemonItems.POISON_GEM)
entries.add(CobblemonItems.GROUND_GEM)
entries.add(CobblemonItems.FLYING_GEM)
entries.add(CobblemonItems.PSYCHIC_GEM)
entries.add(CobblemonItems.BUG_GEM)
entries.add(CobblemonItems.ROCK_GEM)
entries.add(CobblemonItems.GHOST_GEM)
entries.add(CobblemonItems.DRAGON_GEM)
entries.add(CobblemonItems.DARK_GEM)
entries.add(CobblemonItems.STEEL_GEM)
entries.add(CobblemonItems.FAIRY_GEM)
}
private fun blockEntries(displayContext: DisplayContext, entries: Entries) {
@@ -188,6 +219,18 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.PC)
entries.add(CobblemonItems.HEALING_MACHINE)
entries.add(CobblemonItems.PASTURE)
entries.add(CobblemonItems.GILDED_CHEST)
entries.add(CobblemonItems.YELLOW_GILDED_CHEST)
entries.add(CobblemonItems.GREEN_GILDED_CHEST)
entries.add(CobblemonItems.BLUE_GILDED_CHEST)
entries.add(CobblemonItems.PINK_GILDED_CHEST)
entries.add(CobblemonItems.BLACK_GILDED_CHEST)
entries.add(CobblemonItems.WHITE_GILDED_CHEST)
entries.add(CobblemonItems.GIMMIGHOUL_CHEST)
entries.add(CobblemonItems.RELIC_COIN_POUCH)
entries.add(CobblemonItems.RELIC_COIN_SACK)
entries.add(CobblemonItems.APRICORN_LOG)
entries.add(CobblemonItems.APRICORN_WOOD)
entries.add(CobblemonItems.STRIPPED_APRICORN_LOG)
@@ -277,6 +320,13 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.DIRE_HIT)
entries.add(CobblemonItems.GUARD_SPEC)
entries.add(CobblemonItems.HEALTH_FEATHER)
entries.add(CobblemonItems.MUSCLE_FEATHER)
entries.add(CobblemonItems.RESIST_FEATHER)
entries.add(CobblemonItems.GENIUS_FEATHER)
entries.add(CobblemonItems.CLEVER_FEATHER)
entries.add(CobblemonItems.SWIFT_FEATHER)
entries.add(CobblemonItems.HP_UP)
entries.add(CobblemonItems.PROTEIN)
entries.add(CobblemonItems.IRON)
@@ -424,6 +474,25 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.TWISTED_SPOON)
entries.add(CobblemonItems.WHITE_HERB)
entries.add(CobblemonItems.WISE_GLASSES)
entries.add(CobblemonItems.NORMAL_GEM)
entries.add(CobblemonItems.FIRE_GEM)
entries.add(CobblemonItems.WATER_GEM)
entries.add(CobblemonItems.GRASS_GEM)
entries.add(CobblemonItems.ELECTRIC_GEM)
entries.add(CobblemonItems.ICE_GEM)
entries.add(CobblemonItems.FIGHTING_GEM)
entries.add(CobblemonItems.POISON_GEM)
entries.add(CobblemonItems.GROUND_GEM)
entries.add(CobblemonItems.FLYING_GEM)
entries.add(CobblemonItems.PSYCHIC_GEM)
entries.add(CobblemonItems.BUG_GEM)
entries.add(CobblemonItems.ROCK_GEM)
entries.add(CobblemonItems.GHOST_GEM)
entries.add(CobblemonItems.DRAGON_GEM)
entries.add(CobblemonItems.DARK_GEM)
entries.add(CobblemonItems.STEEL_GEM)
entries.add(CobblemonItems.FAIRY_GEM)
}
private fun pokeballentries(displayContext: DisplayContext, entries: Entries) {
@@ -432,9 +501,9 @@ object CobblemonItemGroups {
private fun foodInjections(injector: Injector) {
injector.putLast(CobblemonItems.ROASTED_LEEK)
injector.putLast(CobblemonItems.LEEK_AND_POTATO_STEW)
injector.putLast(CobblemonItems.BRAISED_VIVICHOKE)
injector.putLast(CobblemonItems.VIVICHOKE_DIP)
injector.putAfter(CobblemonItems.LEEK_AND_POTATO_STEW, CobblemonItems.ROASTED_LEEK)
injector.putAfter(CobblemonItems.BRAISED_VIVICHOKE, CobblemonItems.LEEK_AND_POTATO_STEW)
injector.putAfter(CobblemonItems.VIVICHOKE_DIP, CobblemonItems.BRAISED_VIVICHOKE)
}
private fun toolsAndUtilitiesInjections(injector: Injector) {
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item.interactive
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.item.CobblemonItem
import com.cobblemon.mod.common.pokemon.EVs
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundCategory
import net.minecraft.util.Hand
import net.minecraft.util.TypedActionResult
import net.minecraft.world.World
class FeatherItem(val stat: Stat) : CobblemonItem(Settings()), PokemonSelectingItem {
companion object {
const val EV_YIELD = 1
}
override val bagItem = null
override fun canUseOnPokemon(pokemon: Pokemon) = pokemon.evs.getOrDefault(stat) < EVs.MAX_STAT_VALUE
override fun applyToPokemon(
player: ServerPlayerEntity,
stack: ItemStack,
pokemon: Pokemon
): TypedActionResult<ItemStack> {
val evsGained = pokemon.evs.add(stat, EV_YIELD)
return if (evsGained > 0) {
player.playSound(CobblemonSounds.MEDICINE_FEATHER_USE, SoundCategory.PLAYERS, 1F, 1F)
if (!player.isCreative) {
stack.decrement(1)
}
TypedActionResult.success(stack)
} else {
TypedActionResult.fail(stack)
}
}
override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
if (user is ServerPlayerEntity) {
return use(user, user.getStackInHand(hand))
}
return TypedActionResult.success(user.getStackInHand(hand))
}
}
@@ -16,9 +16,13 @@ import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.Natures
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.net.messages.client.pokemon.update.SpeciesFeatureUpdatePacket
import com.cobblemon.mod.common.pokemon.*
import com.cobblemon.mod.common.pokemon.activestate.PokemonState
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
@@ -71,6 +75,8 @@ class PokemonDTO : Encodable, Decodable {
var dmaxLevel = 0
var gmaxFactor = false
var tradeable = true
// var features: List<SynchronizedSpeciesFeature> = emptyList()
lateinit var featuresBuffer: PacketByteBuf
var originalTrainerType: OriginalTrainerType = OriginalTrainerType.NONE
var originalTrainer: String? = null
var originalTrainerName: String? = null
@@ -108,6 +114,15 @@ class PokemonDTO : Encodable, Decodable {
this.dmaxLevel = pokemon.dmaxLevel
this.gmaxFactor = pokemon.gmaxFactor
this.tradeable = pokemon.tradeable
this.featuresBuffer = PacketByteBuf(Unpooled.buffer())
val visibleFeatures = pokemon.features
.filterIsInstance<SynchronizedSpeciesFeature>()
.filter { (SpeciesFeatures.getFeature(it.name)!! as SynchronizedSpeciesFeatureProvider<*>).visible }
featuresBuffer.writeCollection(visibleFeatures) { _, value ->
featuresBuffer.writeString(value.name)
value.encode(featuresBuffer)
}
this.originalTrainerType = pokemon.originalTrainerType
this.originalTrainer = pokemon.originalTrainer
this.originalTrainerName = pokemon.originalTrainerName
@@ -148,6 +163,10 @@ class PokemonDTO : Encodable, Decodable {
buffer.writeInt(dmaxLevel)
buffer.writeBoolean(gmaxFactor)
buffer.writeBoolean(tradeable)
val featureByteCount = featuresBuffer.readableBytes()
buffer.writeSizedInt(IntSize.U_SHORT, featureByteCount)
buffer.writeBytes(featuresBuffer)
featuresBuffer.release()
buffer.writeString(originalTrainerType.name)
buffer.writeNullable(originalTrainer) { _, v -> buffer.writeString(v) }
buffer.writeNullable(originalTrainerName) { _, v -> buffer.writeString(v) }
@@ -189,6 +208,9 @@ class PokemonDTO : Encodable, Decodable {
dmaxLevel = buffer.readInt()
gmaxFactor = buffer.readBoolean()
tradeable = buffer.readBoolean()
val featureBytesToRead = buffer.readSizedInt(IntSize.U_SHORT)
featuresBuffer = PacketByteBuf(buffer.readBytes(featureBytesToRead))
originalTrainerType = OriginalTrainerType.valueOf(buffer.readString())
originalTrainer = buffer.readNullable { buffer.readString() }
originalTrainerName = buffer.readNullable { buffer.readString() }
@@ -204,7 +226,6 @@ class PokemonDTO : Encodable, Decodable {
it.experience = experience
it.level = level
it.setFriendship(friendship)
it.currentHealth = currentHealth
it.gender = gender
ivs.forEach { stat ->
it.setIV(stat.key, stat.value)
@@ -212,6 +233,7 @@ class PokemonDTO : Encodable, Decodable {
evs.forEach { stat ->
it.setEV(stat.key, stat.value)
}
it.currentHealth = currentHealth
it.moveSet.clear()
for (move in moveSet) {
it.moveSet.add(move)
@@ -241,6 +263,17 @@ class PokemonDTO : Encodable, Decodable {
it.dmaxLevel = dmaxLevel
it.gmaxFactor = gmaxFactor
it.tradeable = tradeable
repeat(times = featuresBuffer.readSizedInt(IntSize.U_BYTE)) { _ ->
val species = PokemonSpecies.getByIdentifier(this.species)!!
val speciesFeatureName = featuresBuffer.readString()
val featureProviders = SpeciesFeatures
.getFeaturesFor(species)
.filterIsInstance<SynchronizedSpeciesFeatureProvider<*>>()
val feature = featureProviders.firstNotNullOfOrNull { it(featuresBuffer, speciesFeatureName) } as? SynchronizedSpeciesFeature
?: throw IllegalArgumentException("Couldn't find a feature provider to deserialize this feature. Something's wrong.")
it.features.removeIf { it.name == feature.name }
it.features.add(feature)
}
when (originalTrainerType)
{
OriginalTrainerType.NONE -> {
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.data
import com.cobblemon.mod.common.api.pokemon.feature.GlobalSpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
/**
* Syncs a species feature provider that was registered under [GlobalSpeciesFeatures].
*
* @author Hiroku
* @since November 13th, 2023
*/
class GlobalSpeciesFeatureSyncPacket(speciesFeatures: Map<String, SpeciesFeatureProvider<*>>) : SpeciesFeatureSyncPacket(speciesFeatures) {
override val id = ID
override fun synchronizeDecoded(entries: Collection<Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>>) = GlobalSpeciesFeatures.loadOnClient(entries)
companion object {
val ID = cobblemonResource("global_species_feature_sync")
fun decode(buffer: PacketByteBuf) = GlobalSpeciesFeatureSyncPacket(emptyMap()).apply { decodeBuffer(buffer) }
}
}
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.data
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureAssignments
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
/**
* A registry sync packet for the [SpeciesFeatureAssignments] registry.
*
* @author Hiroku
* @since November 13th, 2023
*/
class SpeciesFeatureAssignmentSyncPacket(
data: Map<Identifier, MutableSet<String>>
) : DataRegistrySyncPacket<Map.Entry<Identifier, MutableSet<String>>, SpeciesFeatureAssignmentSyncPacket>(data.entries) {
override val id = ID
override fun decodeEntry(buffer: PacketByteBuf): Map.Entry<Identifier, MutableSet<String>> {
val key = buffer.readIdentifier()
val assignments = buffer.readList { buffer.readString() }.toMutableSet()
return object : Map.Entry<Identifier, MutableSet<String>> {
override val key = key
override val value = assignments
}
}
override fun encodeEntry(buffer: PacketByteBuf, entry: Map.Entry<Identifier, MutableSet<String>>) {
buffer.writeIdentifier(entry.key)
buffer.writeCollection(entry.value) { _, value -> buffer.writeString(value) }
}
override fun synchronizeDecoded(entries: Collection<Map.Entry<Identifier, MutableSet<String>>>) {
SpeciesFeatureAssignments.loadOnClient(entries.associate { it.toPair() })
}
companion object {
val ID = cobblemonResource("species_feature_assignment_sync")
fun decode(buffer: PacketByteBuf) = SpeciesFeatureAssignmentSyncPacket(emptyMap()).apply { decodeBuffer(buffer) }
}
}
@@ -0,0 +1,68 @@
/*
* 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.net.messages.client.data
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import net.minecraft.network.PacketByteBuf
/**
* Base class for a registry sync packet that synchronizes [SynchronizedSpeciesFeatureProvider]s.
*
* @author Hiroku
* @since November 13th, 2023
*/
abstract class SpeciesFeatureSyncPacket(
speciesFeatureProviders: Map<String, SpeciesFeatureProvider<*>>
) : DataRegistrySyncPacket<Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>, SpeciesFeatureSyncPacket>(
speciesFeatureProviders.entries.filterIsInstance<Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>>().filter { it.value.visible }
) {
override fun encodeEntry(buffer: PacketByteBuf, entry: Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>) {
val typeName = SpeciesFeatures.types.entries.find { it.value.isInstance(entry.value) }?.key
val value = entry.value
if (typeName == null) {
buffer.writeBoolean(false)
return
} else {
buffer.writeBoolean(true)
}
buffer.writeString(entry.key)
buffer.writeString(typeName)
value.encode(buffer)
}
override fun decodeEntry(buffer: PacketByteBuf): Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>? {
if (!buffer.readBoolean()) {
return null
}
val name = buffer.readString()
val typeName = buffer.readString()
val typeClass = SpeciesFeatures.types[typeName]
?: throw IllegalStateException(
"""
A custom species feature provider, $typeName with encoding implementations was registered on the server and
not the client, and therefore cannot be synced. Remove the implementation or install it
on the client.
""".trimIndent()
)
val instance = typeClass.getConstructor().newInstance()
if (instance !is SynchronizedSpeciesFeatureProvider) {
throw IllegalStateException("Somehow a non-SynchronizedSpeciesFeatureProvider was sent to the client. Version mismatch?")
} else {
instance.decode(buffer)
}
return object : Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>> {
override val key: String = name
override val value: SynchronizedSpeciesFeatureProvider<*> = instance
}
}
}
@@ -0,0 +1,31 @@
/*
* 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.net.messages.client.data
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
/**
* Syncs a species feature provider that was registered under [SpeciesFeatures].
*
* @author Hiroku
* @since November 13th, 2023
*/
class StandardSpeciesFeatureSyncPacket(providers: Map<String, SpeciesFeatureProvider<*>>) : SpeciesFeatureSyncPacket(providers) {
override val id: Identifier = ID
override fun synchronizeDecoded(entries: Collection<Map.Entry<String, SynchronizedSpeciesFeatureProvider<*>>>) = SpeciesFeatures.loadOnClient(entries)
companion object {
val ID = cobblemonResource("standard_species_feature_sync")
fun decode(buffer: PacketByteBuf) = StandardSpeciesFeatureSyncPacket(emptyMap()).apply { decodeBuffer(buffer) }
}
}
@@ -0,0 +1,53 @@
/*
* 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.net.messages.client.pokemon.update
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
/**
* Updates the state of a particular [SynchronizedSpeciesFeature].
*
* @author Hiroku
* @since November 13th, 2023
*/
class SpeciesFeatureUpdatePacket(pokemon: () -> Pokemon, val species: Identifier, speciesFeature: SynchronizedSpeciesFeature) : SingleUpdatePacket<SynchronizedSpeciesFeature, SpeciesFeatureUpdatePacket>(pokemon, speciesFeature) {
companion object {
val ID = cobblemonResource("species_feature_update")
fun decode(buffer: PacketByteBuf): SpeciesFeatureUpdatePacket {
val pokemon = decodePokemon(buffer)
val speciesIdentifier = buffer.readIdentifier()
val species = PokemonSpecies.getByIdentifier(speciesIdentifier)
?: throw IllegalStateException("Pokémon unable to be found during species feature update packet: $speciesIdentifier")
val speciesFeatureName = buffer.readString()
val featureProviders = SpeciesFeatures.getFeaturesFor(species).filterIsInstance<SynchronizedSpeciesFeatureProvider<*>>()
val feature = featureProviders.firstNotNullOfOrNull { it(buffer, speciesFeatureName) } as? SynchronizedSpeciesFeature
?: throw IllegalArgumentException("Couldn't find a feature provider to deserialize this feature. Something's wrong.")
return SpeciesFeatureUpdatePacket(pokemon, speciesIdentifier, feature)
}
}
override val id = ID
override fun encodeValue(buffer: PacketByteBuf) {
buffer.writeIdentifier(species)
buffer.writeString(value.name)
value.encode(buffer)
}
override fun set(pokemon: Pokemon, value: SynchronizedSpeciesFeature) {
pokemon.features.removeIf { it.name == value.name }
pokemon.features.add(value)
}
}
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.cobblemonResource
@@ -39,6 +38,7 @@ class SpawnPokemonPacket(
private val unbattlable: Boolean,
private val hideLabel: Boolean,
private val caughtBall: Identifier,
private val spawnYaw: Float,
vanillaSpawnPacket: EntitySpawnS2CPacket
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
@@ -59,6 +59,7 @@ class SpawnPokemonPacket(
entity.dataTracker.get(PokemonEntity.UNBATTLEABLE),
entity.dataTracker.get(PokemonEntity.HIDE_LABEL),
entity.pokemon.caughtBall.name,
entity.dataTracker.get(PokemonEntity.SPAWN_DIRECTION),
vanillaSpawnPacket
)
@@ -77,6 +78,7 @@ class SpawnPokemonPacket(
buffer.writeBoolean(this.unbattlable)
buffer.writeBoolean(this.hideLabel)
buffer.writeIdentifier(this.caughtBall)
buffer.writeFloat(this.spawnYaw)
}
override fun applyData(entity: PokemonEntity) {
@@ -98,6 +100,7 @@ class SpawnPokemonPacket(
entity.dataTracker.set(PokemonEntity.POSE_TYPE, poseType)
entity.dataTracker.set(PokemonEntity.UNBATTLEABLE, unbattlable)
entity.dataTracker.set(PokemonEntity.HIDE_LABEL, hideLabel)
entity.dataTracker.set(PokemonEntity.SPAWN_DIRECTION, spawnYaw)
}
override fun checkType(entity: Entity): Boolean = entity is PokemonEntity
@@ -120,8 +123,10 @@ class SpawnPokemonPacket(
val unbattlable = buffer.readBoolean()
val hideLabel = buffer.readBoolean()
val caughtBall = buffer.readIdentifier()
val spawnAngle = buffer.readFloat()
val vanillaPacket = decodeVanillaPacket(buffer)
return SpawnPokemonPacket(ownerId, scaleModifier, species, form, aspects, battleId, phasingTargetId, beamModeEmitter, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, vanillaPacket)
return SpawnPokemonPacket(ownerId, scaleModifier, species, form, aspects, battleId, phasingTargetId, beamModeEmitter, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, vanillaPacket)
}
}
@@ -0,0 +1,32 @@
/*
* 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.net.messages.server.battle
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import java.util.UUID
class FleeBattlePacket(val battleId: UUID) : NetworkPacket<FleeBattlePacket> {
override val id = ID
override fun encode(buffer: PacketByteBuf) {
buffer.writeUuid(battleId)
}
companion object {
val ID = cobblemonResource("flee_battle")
fun decode(buffer: PacketByteBuf): FleeBattlePacket {
return FleeBattlePacket(buffer.readUuid())
}
}
}
@@ -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.net.serverhandling.battle
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
import com.cobblemon.mod.common.util.battleLang
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
object FleeBattlePacketHandler : ServerNetworkPacketHandler<FleeBattlePacket> {
override fun handle(packet: FleeBattlePacket, server: MinecraftServer, player: ServerPlayerEntity) {
val battle = BattleRegistry.getBattle(packet.battleId) ?: return
player.sendMessage(battleLang("flee"))
battle.end()
}
}
@@ -18,8 +18,10 @@ import com.cobblemon.mod.common.api.abilities.Ability
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.FRIENDSHIP_UPDATED
import com.cobblemon.mod.common.api.events.CobblemonEvents.HELD_ITEM_UPDATED
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_FAINTED
import com.cobblemon.mod.common.api.events.pokemon.*
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
import com.cobblemon.mod.common.api.moves.*
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.Natures
@@ -32,6 +34,7 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroup
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceSource
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.friendship.FriendshipMutationCalculator
import com.cobblemon.mod.common.api.pokemon.labels.CobblemonPokemonLabels
import com.cobblemon.mod.common.api.pokemon.moves.LearnsetQuery
@@ -59,6 +62,7 @@ import com.cobblemon.mod.common.pokemon.evolution.CobblemonEvolutionProxy
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
import com.cobblemon.mod.common.pokemon.feature.SeasonFeatureHandler
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.pokemon.status.PersistentStatusContainer
@@ -109,9 +113,11 @@ open class Pokemon : ShowdownIdentifiable {
}
val quotient = clamp(currentHealth / hp.toFloat(), 0F, 1F)
field = value
val newFeatures = SpeciesFeatures.getFeaturesFor(species).mapNotNull { it.invoke(this) }
features.clear()
features.addAll(newFeatures)
if (!isClient) {
val newFeatures = SpeciesFeatures.getFeaturesFor(species).mapNotNull { it.invoke(this) }
features.clear()
features.addAll(newFeatures)
}
this.evolutionProxy.current().clear()
updateAspects()
updateForm()
@@ -253,6 +259,7 @@ open class Pokemon : ShowdownIdentifiable {
_friendship.emit(it.newFriendship)
}
}
var state: PokemonState = InactivePokemonState()
set(value) {
field = value
@@ -685,7 +692,9 @@ open class Pokemon : ShowdownIdentifiable {
}
this.heldItem = giving
this._heldItem.emit(giving)
CobblemonEvents.HELD_ITEM_POST.post(HeldItemEvent.Post(this, this.heldItem(), event.returning.copy(), event.decrement))
CobblemonEvents.HELD_ITEM_POST.post(HeldItemEvent.Post(this, this.heldItem(), event.returning.copy(), event.decrement)) {
GimmighoulStashHandler.giveHeldItem(it)
}
return event.returning
})
return stack
@@ -1411,11 +1420,14 @@ open class Pokemon : ShowdownIdentifiable {
storeCoordinates.get()?.run { sendPacketToPlayers(store.getObservingPlayers(), packet) }
}
fun <T> registerObservable(observable: SimpleObservable<T>, notifyPacket: ((T) -> PokemonUpdatePacket<*>)? = null): SimpleObservable<T> {
fun <T> registerObservable(observable: SimpleObservable<T>, notifyPacket: ((T) -> PokemonUpdatePacket<*>?)? = null): SimpleObservable<T> {
observables.add(observable)
observable.subscribe {
if (notifyPacket != null && storeCoordinates.get() != null) {
notify(notifyPacket(it))
val packet = notifyPacket(it)
if (packet != null) {
notify(packet)
}
}
anyChangeObservable.emit(this)
}
@@ -1505,7 +1517,13 @@ open class Pokemon : ShowdownIdentifiable {
private val _gmaxFactor = registerObservable(SimpleObservable<Boolean>()) { GmaxFactorUpdatePacket({ this }, it) }
private val _originalTrainerName = registerObservable(SimpleObservable<String?>()) { OriginalTrainerUpdatePacket({ this }, it) }
private val _features = registerObservable(SimpleObservable<SpeciesFeature>())
private val _features = registerObservable(SimpleObservable<SpeciesFeature>()) {
if (it is SynchronizedSpeciesFeature) {
SpeciesFeatureUpdatePacket({ this }, species.resourceIdentifier, it)
} else {
null
}
}
companion object {
/**
@@ -199,6 +199,7 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
buffer.writeCollection(this.pokedex) { pb, line -> pb.writeString(line) }
buffer.writeCollection(this.forms) { pb, form -> form.encode(pb) }
buffer.writeIdentifier(this.battleTheme)
buffer.writeCollection(this.features) { pb, feature -> pb.writeString(feature) }
buffer.writeNullable(this.lightingData) { pb, data ->
pb.writeInt(data.lightLevel)
pb.writeEnumConstant(data.liquidGlowMode)
@@ -226,6 +227,8 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
this.forms.clear()
this.forms += buffer.readList{ pb -> FormData().apply { decode(pb) } }.filterNotNull()
this.battleTheme = buffer.readIdentifier()
this.features.clear()
this.features += buffer.readList { pb -> pb.readString() }
this.lightingData = buffer.readNullable { pb -> LightingData(pb.readInt(), pb.readEnumConstant(LightingData.LiquidGlowMode::class.java)) }
this.initialize()
}
@@ -248,6 +251,7 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
// We only sync level up moves atm
|| this.moves.shouldSynchronize(other.moves)
|| other.battleTheme != this.battleTheme
|| other.features != this.features
}
/**
@@ -18,6 +18,7 @@ import java.util.EnumSet
import net.minecraft.block.AbstractRailBlock
import net.minecraft.block.Blocks
import net.minecraft.block.FenceGateBlock
import net.minecraft.entity.ai.pathing.LandPathNodeMaker
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.ai.pathing.PathNode
import net.minecraft.entity.ai.pathing.PathNodeMaker
@@ -229,7 +230,8 @@ class OmniPathNodeMaker : PathNodeMaker() {
val isWater = blockState.fluidState.isIn(FluidTags.WATER)
val isLava = blockState.fluidState.isIn(FluidTags.LAVA)
val canBreatheUnderFluid = canSwimUnderFluid(blockState.fluidState)
return if (blockStateBelow.isIn(BlockTags.FENCES) || blockStateBelow.isIn(BlockTags.WALLS) || (blockStateBelow.block is FenceGateBlock && !blockStateBelow.get(FenceGateBlock.OPEN))) {
val figuredNode = if (blockStateBelow.isIn(BlockTags.FENCES) || blockStateBelow.isIn(BlockTags.WALLS) || (blockStateBelow.block is FenceGateBlock && !blockStateBelow.get(FenceGateBlock.OPEN))) {
PathNodeType.FENCE
} else if (isWater && belowSolid && !canSwimInWater() && canBreatheUnderFluid) {
PathNodeType.WALKABLE
@@ -240,6 +242,8 @@ class OmniPathNodeMaker : PathNodeMaker() {
} else if (blockState.canPathfindThrough(world, pos, NavigationType.AIR) && blockStateBelow.canPathfindThrough(world, below, NavigationType.AIR)) {
PathNodeType.OPEN
} else PathNodeType.BLOCKED
return adjustNodeType(world, canOpenDoors, canEnterOpenDoors, below, figuredNode)
}
override fun getNodeType(world: BlockView, x: Int, y: Int, z: Int, mob: MobEntity): PathNodeType? {
@@ -249,6 +253,11 @@ class OmniPathNodeMaker : PathNodeMaker() {
val sizeZ = (mob.boundingBox.maxZ - mob.boundingBox.minZ).toInt() + 1
val type = findNearbyNodeTypes(world, x, y, z, sizeX, sizeY, sizeZ, canOpenDoors, canEnterOpenDoors, set, PathNodeType.BLOCKED, BlockPos(x, y, z))
if (PathNodeType.DAMAGE_CAUTIOUS in set) {
return PathNodeType.DAMAGE_CAUTIOUS
} else if (PathNodeType.DANGER_OTHER in set) {
return PathNodeType.DANGER_OTHER
}
return if (PathNodeType.FENCE in set) {
PathNodeType.FENCE
} else if (PathNodeType.UNPASSABLE_RAIL in set) {
@@ -299,8 +308,7 @@ class OmniPathNodeMaker : PathNodeMaker() {
val l = i + x
val m = j + y
val n = k + z
var pathNodeType = getDefaultNodeType(world, l, m, n)
pathNodeType = this.adjustNodeType(world, canOpenDoors, canEnterOpenDoors, pos, pathNodeType)
val pathNodeType = getDefaultNodeType(world, l, m, n)
if (i == 0 && j == 0 && k == 0) {
type = pathNodeType
}
@@ -318,18 +326,34 @@ class OmniPathNodeMaker : PathNodeMaker() {
pos: BlockPos,
type: PathNodeType
): PathNodeType {
val block = world.getBlockState(pos).block
val blockState = world.getBlockState(pos)
val block = blockState.block
if (blockState.isOf(Blocks.CACTUS) || blockState.isOf(Blocks.SWEET_BERRY_BUSH)) {
return PathNodeType.DANGER_OTHER
}
if (LandPathNodeMaker.inflictsFireDamage(blockState) && !entity.isFireImmune) {
return PathNodeType.DANGER_FIRE
}
if (world.getFluidState(pos).isIn(FluidTags.WATER)) {
return PathNodeType.WATER_BORDER
}
if (blockState.isOf(Blocks.WITHER_ROSE) || blockState.isOf(Blocks.POINTED_DRIPSTONE)) {
return PathNodeType.DAMAGE_CAUTIOUS
}
return if (type == PathNodeType.DOOR_WOOD_CLOSED && canOpenDoors && canEnterOpenDoors) {
PathNodeType.WALKABLE_DOOR
}else if (type == PathNodeType.DOOR_OPEN && !canEnterOpenDoors) {
} else if (type == PathNodeType.DOOR_OPEN && !canEnterOpenDoors) {
PathNodeType.BLOCKED
}else if (type == PathNodeType.RAIL && block !is AbstractRailBlock && world.getBlockState(pos.down()).block !is AbstractRailBlock) {
} else if (type == PathNodeType.RAIL && block !is AbstractRailBlock && world.getBlockState(pos.down()).block !is AbstractRailBlock) {
PathNodeType.UNPASSABLE_RAIL
}else if (type == PathNodeType.LEAVES) {
} else if (type == PathNodeType.LEAVES) {
PathNodeType.BLOCKED
}else if(block == Blocks.SWEET_BERRY_BUSH){
PathNodeType.DANGER_OTHER
}else type
} else type
}
fun canWalk(): Boolean {
@@ -53,6 +53,7 @@ object CobblemonRequirementAdapter : RequirementAdapter {
this.registerType(BlocksTraveledRequirement.ADAPTER_VARIANT, BlocksTraveledRequirement::class)
this.registerType(StructureRequirement.ADAPTER_VARIANT, StructureRequirement::class)
this.registerType(AnyRequirement.ADAPTER_VARIANT, AnyRequirement::class)
this.registerType(PropertyRangeRequirement.ADAPTER_VARIANT, PropertyRangeRequirement::class)
this.registerType(PlayerHasAdvancementRequirement.ADAPTER_VARIANT, PlayerHasAdvancementRequirement::class)
}
@@ -0,0 +1,27 @@
/*
* 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.pokemon.evolution.requirements
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeature
import com.cobblemon.mod.common.pokemon.Pokemon
class PropertyRangeRequirement : EvolutionRequirement {
val range = IntRange(0, 256)
val feature: String = ""
override fun check(pokemon: Pokemon): Boolean {
val feature: IntSpeciesFeature = pokemon.getFeature(feature) ?: return false
return this.range.contains(feature.value)
}
companion object {
const val ADAPTER_VARIANT = "property_range"
}
}
@@ -36,7 +36,7 @@ open class ItemInteractionEvolution(
override var optional: Boolean,
override var consumeHeldItem: Boolean,
override val requirements: MutableSet<EvolutionRequirement>,
override val learnableMoves: MutableSet<MoveTemplate>
override val learnableMoves: MutableSet<MoveTemplate>,
) : ContextEvolution<ItemInteractionEvolution.ItemInteractionContext, NbtItemPredicate> {
constructor(): this(
id = "id",
@@ -28,7 +28,8 @@ open class LevelUpEvolution(
override var optional: Boolean,
override var consumeHeldItem: Boolean,
override val requirements: MutableSet<EvolutionRequirement>,
override val learnableMoves: MutableSet<MoveTemplate>
override val learnableMoves: MutableSet<MoveTemplate>,
override val permanent: Boolean
) : PassiveEvolution {
/* Needed for old Gson versions that MC ships with */
@@ -38,7 +39,8 @@ open class LevelUpEvolution(
optional = true,
consumeHeldItem = true,
requirements = mutableSetOf(),
learnableMoves = mutableSetOf()
learnableMoves = mutableSetOf(),
permanent = false
)
override fun equals(other: Any?) = other is LevelUpEvolution && other.id.equals(this.id, true)
@@ -0,0 +1,73 @@
/*
* 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.pokemon.misc
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.events.pokemon.HeldItemEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeature
import net.minecraft.item.Items
import net.minecraft.sound.SoundCategory
/**
* Handles logic relating to Gimmighoul's Coin Stash and Scrap Stash bars.
*
* @author whatsy
*/
object GimmighoulStashHandler {
val COIN_VALUE = 1
val POUCH_VALUE = COIN_VALUE * 9
val SACK_VALUE = POUCH_VALUE * 9
val SCRAP_VALUE = 1
val INGOT_VALUE = SCRAP_VALUE * 4
val BLOCK_VALUE = INGOT_VALUE * 9
fun giveHeldItem(event: HeldItemEvent.Post) {
val goldHoard = event.pokemon.getFeature<IntSpeciesFeature>("gimmighoul_coins")
val netheriteHoard = event.pokemon.getFeature<IntSpeciesFeature>("gimmighoul_netherite")
if (goldHoard != null && goldHoard.value < 999) {
val increase = when (event.received.item) {
CobblemonItems.RELIC_COIN -> COIN_VALUE
CobblemonItems.RELIC_COIN_POUCH -> POUCH_VALUE
CobblemonItems.RELIC_COIN_SACK -> SACK_VALUE
else -> 0
}
if (increase != 0) {
goldHoard.value += increase
if (goldHoard.value > 999) goldHoard.value = 999
if (event.pokemon.entity != null) event.pokemon.entity!!.playSound(CobblemonSounds.GIMMIGHOUL_GIVE_ITEM_SMALL, 1f, 1f)
event.pokemon.markFeatureDirty(goldHoard)
event.pokemon.removeHeldItem()
}
}
if (netheriteHoard != null && netheriteHoard.value < 256) {
val increase = when (event.received.item) {
Items.NETHERITE_SCRAP -> SCRAP_VALUE
Items.NETHERITE_INGOT -> INGOT_VALUE
Items.NETHERITE_BLOCK -> BLOCK_VALUE
else -> 0
}
if (increase != 0) {
netheriteHoard.value += increase
if (netheriteHoard.value > 256) netheriteHoard.value = 256
if (event.pokemon.entity != null) event.pokemon.entity!!.playSound(CobblemonSounds.GIMMIGHOUL_GIVE_ITEM_SMALL, 1f, 1f)
event.pokemon.markFeatureDirty(netheriteHoard)
event.pokemon.removeHeldItem()
}
}
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.util
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class MutableLazy<T>(private var initializer: (() -> T)?) : ReadWriteProperty<Any?, T> {
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
if (value == null) {
value = initializer?.invoke()
initializer = null
}
return value!!
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
}
fun <T> mutableLazy(initializer: () -> T) = MutableLazy(initializer)
@@ -122,7 +122,7 @@ fun getRotationMatrix(from: Vec3d, to: Vec3d): Matrix3f {
q.rotateTo(Vector3f(from.x.toFloat(), from.y.toFloat(), from.z.toFloat()), Vector3f(to.x.toFloat(), to.y.toFloat(), to.z.toFloat()))
val m = Matrix3f()
return m.identity().rotation(q)
/**
val v = from.crossProduct(to)
val c = from.dotProduct(to)
@@ -152,6 +152,7 @@ fun getRotationMatrix(from: Vec3d, to: Vec3d): Matrix3f {
r.add(vx2)
return r
**/
}
operator fun Matrix3f.times(vec3d: Vec3d): Vec3d {
@@ -15,7 +15,7 @@ object CobblemonStructureProcessorListOverrides {
val registryKey = RegistryKeys.PROCESSOR_LIST
fun register(server: MinecraftServer) {
val registry = server.registryManager.get(registryKey)
//val registry = server.registryManager.get(registryKey)
// registerFarmOverrides(registry)
}
@@ -0,0 +1,9 @@
{
"sources": [
{
"type": "directory",
"source": "entity/chest",
"prefix": "entity/chest/"
}
]
}
@@ -0,0 +1,264 @@
{
"format_version": "1.8.0",
"animations": {
"animation.gilded_chest.opening": {
"loop": "hold_on_last_frame",
"animation_length": 0.25,
"bones": {
"lid": {
"rotation": {
"0.0": [0, 0, 0],
"0.125": [-27.15, 0, 0],
"0.1667": [-33, 0, 0],
"0.2083": [-36.5, 0, 0],
"0.25": [-37.5, 0, 0]
}
},
"belt_top4": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.0833": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [4.22, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [5, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom2": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [65.2, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [80, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom3": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.0417": {
"post": [-14.19, 0, 0],
"lerp_mode": "catmullrom"
},
"0.125": {
"post": [-22, 0, 0],
"lerp_mode": "catmullrom"
},
"0.2083": {
"post": [-3.93, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom4": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.0417": {
"post": [-15.24, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [-26.68, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
}
}
}
}
},
"animation.gilded_chest.open": {
"loop": true,
"bones": {
"lid": {
"rotation": [-37.5, 0, 0]
},
"belt_top4": {
"rotation": {
"0.0": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom": {
"rotation": {
"0.0": {
"post": [5, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom2": {
"rotation": {
"0.0": {
"post": [80, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom3": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom4": {
"rotation": {
"0.0": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
}
}
}
}
},
"animation.gilded_chest.closing": {
"loop": "hold_on_last_frame",
"animation_length": 0.25,
"bones": {
"lid": {
"rotation": {
"0.0": [-37.5, 0, 0],
"0.25": [0, 0, 0]
}
},
"belt_top4": {
"rotation": {
"0.0": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.0833": {
"post": [-20.8, 0, 0],
"lerp_mode": "catmullrom"
},
"0.2083": {
"post": [-18.4, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom": {
"rotation": {
"0.0": {
"post": [5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom2": {
"rotation": {
"0.0": {
"post": [80, 0, 0],
"lerp_mode": "catmullrom"
},
"0.0833": {
"post": [67, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [13.3, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom3": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.0833": {
"post": [15, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [11.6, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"belt_bottom4": {
"rotation": {
"0.0": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
},
"0.0417": {
"post": [-1.88, 0, 0],
"lerp_mode": "catmullrom"
},
"0.125": {
"post": [18.76, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
}
}
}
}
}
@@ -0,0 +1,169 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.gilded_chest",
"texture_width": 64,
"texture_height": 64,
"visible_bounds_width": 2,
"visible_bounds_height": 2.5,
"visible_bounds_offset": [0, 0.75, 0]
},
"bones": [
{
"name": "gilded_chest",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "gilded_chest",
"pivot": [0, 8, -1.5]
},
{
"name": "chest",
"parent": "body",
"pivot": [0, 7, 0],
"cubes": [
{"origin": [6, 5, -5.5], "size": [1, 1, 8], "uv": [38, 51]},
{"origin": [-7, 5, -5.5], "size": [1, 1, 8], "uv": [34, 29], "mirror": true},
{"origin": [-7, 5, -6.5], "size": [14, 1, 1], "uv": [31, 1]},
{"origin": [-7, 5, 2.5], "size": [14, 1, 1], "uv": [31, 3]},
{"origin": [-7, 1, -6.5], "size": [14, 4, 10], "uv": [0, 50]}
]
},
{
"name": "lid",
"parent": "chest",
"pivot": [0, 6, 3.5],
"cubes": [
{"origin": [-8, 14, -7], "size": [16, 1, 11], "uv": [0, 38]},
{"origin": [7, 6, -6], "size": [1, 8, 9], "uv": [43, 32]},
{"origin": [-8, 6, -6], "size": [1, 8, 9], "uv": [40, 8], "mirror": true},
{"origin": [-8, 6, -7], "size": [16, 8, 1], "uv": [0, 29]},
{"origin": [-8, 6, 3], "size": [16, 8, 1], "uv": [0, 19]},
{"origin": [5, 15, -7], "size": [3, 1, 11], "uv": [23, 17]},
{"origin": [-8, 15, -7], "size": [3, 1, 11], "uv": [21, 5], "mirror": true}
]
},
{
"name": "belt_top",
"parent": "lid",
"pivot": [0, 6, 4],
"cubes": [
{"origin": [-1.5, 6, 4], "size": [3, 9, 0], "inflate": 0.02, "uv": [55, 31]}
]
},
{
"name": "belt_top2",
"parent": "belt_top",
"pivot": [0, 15, 4],
"cubes": [
{"origin": [-1.5, 15, -7], "size": [3, 0, 11], "inflate": 0.02, "uv": [46, 51]}
]
},
{
"name": "belt_top3",
"parent": "belt_top2",
"pivot": [0, 15, -7],
"cubes": [
{"origin": [-1.5, 10, -7], "size": [3, 5, 0], "inflate": 0.01, "uv": [50, 51]}
]
},
{
"name": "belt_top4",
"parent": "belt_top3",
"pivot": [0, 10, -7],
"cubes": [
{"origin": [-1.5, 8, -7], "size": [3, 2, 0], "inflate": 0.02, "uv": [50, 56]},
{"origin": [-2, 6, -8], "size": [4, 4, 1], "uv": [0, 50]}
]
},
{
"name": "belt",
"parent": "chest",
"pivot": [0, 1, 3.5]
},
{
"name": "belt_back",
"parent": "belt",
"pivot": [0, 1, 3.5],
"rotation": [-5.7, 0, 0],
"cubes": [
{"origin": [-1.5, 1, 3.5], "size": [3, 5, 0], "inflate": 0.02, "uv": [45, 30]}
]
},
{
"name": "belt_bottom",
"parent": "belt",
"pivot": [0, 1, 3.5],
"cubes": [
{"origin": [-1.5, 1, -6.5], "size": [3, 0, 10], "inflate": 0.02, "uv": [42, 6]}
]
},
{
"name": "belt_bottom2",
"parent": "belt_bottom",
"pivot": [0, 1, -6.5],
"rotation": [6, 0, 0],
"cubes": [
{"origin": [-1.5, 1, -6.5], "size": [3, 2, 0], "inflate": 0.02, "uv": [42, 9]}
]
},
{
"name": "belt_bottom3",
"parent": "belt_bottom2",
"pivot": [0, 3, -6.5],
"cubes": [
{"origin": [-1.5, 3, -6.5], "size": [3, 3, 0], "inflate": 0.02, "uv": [42, 6]}
]
},
{
"name": "belt_bottom4",
"parent": "belt_bottom3",
"pivot": [0, 6, -6.5],
"cubes": [
{"origin": [-1.5, 6, -6.5], "size": [3, 2, 0], "inflate": 0.02, "uv": [42, 11]}
]
},
{
"name": "chest_legs",
"parent": "chest",
"pivot": [0, 1, 0]
},
{
"name": "chest_leg_front_left",
"parent": "chest_legs",
"pivot": [8, 1, -7],
"cubes": [
{"origin": [5, 0, -6.5], "size": [2, 1, 2], "uv": [0, 41]}
]
},
{
"name": "chest_leg_front_right",
"parent": "chest_legs",
"pivot": [-8, 1, -7],
"cubes": [
{"origin": [-7, 0, -6.5], "size": [2, 1, 2], "uv": [0, 38], "mirror": true}
]
},
{
"name": "chest_leg_back_left",
"parent": "chest_legs",
"pivot": [8, 1, 7],
"cubes": [
{"origin": [5, 0, 1.5], "size": [2, 1, 2], "uv": [0, 55]}
]
},
{
"name": "chest_leg_back_right",
"parent": "chest_legs",
"pivot": [-8, 1, 7],
"cubes": [
{"origin": [-7, 0, 1.5], "size": [2, 1, 2], "uv": [0, 44], "mirror": true}
]
}
]
}
]
}
@@ -0,0 +1,9 @@
{
"maxScale": 0.7,
"yTranslation": -0.2,
"animations": [
"bedrock(gilded_chest, opening)",
"bedrock(gilded_chest, open)",
"bedrock(gilded_chest, closing)"
]
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:black_gilded_chest",
"order": 1,
"variations": [
{
"aspects": [],
"poser": "cobblemon:gilded_chest",
"model": "cobblemon:gilded_chest.geo",
"texture": "cobblemon:textures/block/black_gilded_chest.png",
"layers": []
}
]
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:blue_gilded_chest",
"order": 1,
"variations": [
{
"aspects": [],
"poser": "cobblemon:gilded_chest",
"model": "cobblemon:gilded_chest.geo",
"texture": "cobblemon:textures/block/blue_gilded_chest.png",
"layers": []
}
]
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:gilded_chest",
"order": 0,
"variations": [
{
"aspects": [],
"poser": "cobblemon:gilded_chest",
"model": "cobblemon:gilded_chest.geo",
"texture": "cobblemon:textures/block/gilded_chest.png",
"layers": []
}
]
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:green_gilded_chest",
"order": 1,
"variations": [
{
"aspects": [],
"poser": "cobblemon:gilded_chest",
"model": "cobblemon:gilded_chest.geo",
"texture": "cobblemon:textures/block/green_gilded_chest.png",
"layers": []
}
]
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:pink_gilded_chest",
"order": 1,
"variations": [
{
"aspects": [],
"poser": "cobblemon:gilded_chest",
"model": "cobblemon:gilded_chest.geo",
"texture": "cobblemon:textures/block/pink_gilded_chest.png",
"layers": []
}
]
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:white_gilded_chest",
"order": 1,
"variations": [
{
"aspects": [],
"poser": "cobblemon:gilded_chest",
"model": "cobblemon:gilded_chest.geo",
"texture": "cobblemon:textures/block/white_gilded_chest.png",
"layers": []
}
]
}
@@ -0,0 +1,13 @@
{
"name": "cobblemon:yellow_gilded_chest",
"order": 1,
"variations": [
{
"aspects": [],
"poser": "cobblemon:gilded_chest",
"model": "cobblemon:gilded_chest.geo",
"texture": "cobblemon:textures/block/yellow_gilded_chest.png",
"layers": []
}
]
}
@@ -5,44 +5,343 @@
"loop": true,
"bones": {
"body": {
"rotation": [-40, 5, -5],
"position": [0, 2, 1]
"rotation": ["-36+math.sin(q.anim_time*90*0.5-180)*3", "13+math.sin(q.anim_time*90*0.75-60)*-2", "-15+math.sin(q.anim_time*90*1)*1"],
"position": ["-0.75+math.sin(q.anim_time*90*0.25)*0.2", "1.25+math.sin(q.anim_time*90*0.5-45)*0.8", "1+math.sin(q.anim_time*90*0.25-90)*0.1"]
},
"leg_front_right": {
"rotation": [0, -25, 0]
"rotation": ["math.sin(q.anim_time*90*0.5-140)*-6", -25, 0]
},
"leg_back_right": {
"rotation": [0, -25, 0]
"rotation": ["math.sin(q.anim_time*90*0.5-210)*-6", -25, 0]
},
"leg_front_left": {
"rotation": [0, 25, 0]
"rotation": ["math.sin(q.anim_time*90*0.5-120)*-6", 25, 0]
},
"leg_back_left": {
"rotation": [0, 25, 0]
"rotation": ["math.sin(q.anim_time*90*0.5-180)*-6", 25, 0]
},
"tail": {
"rotation": [-30, 0, 0]
"rotation": ["-30+math.sin(q.anim_time*90*0.5-210)*-6", 0, 0]
},
"head": {
"rotation": [60, 0, 5]
"rotation": ["60+math.sin(q.anim_time*90*0.5-20)*9", 0, 5]
},
"neck": {
"rotation": [10, -10, 5]
"rotation": ["18+math.sin(q.anim_time*90*0.5-210)*4", -17, 3.5]
},
"neck3": {
"rotation": [40, 0, 0]
"rotation": ["40+math.sin(q.anim_time*90*0.5-310)*6", -4, 4]
},
"fin_right": {
"rotation": [0, -20, 0]
"rotation": [0, "-20+math.sin(q.anim_time*90*0.5-30)*-12", 0]
},
"fin_left": {
"rotation": [0, 20, 0]
"rotation": [0, "20+math.sin(q.anim_time*90*0.5-30)*15", 0]
},
"tail2": {
"rotation": [-30, 0, 0]
"rotation": ["-30+math.sin(q.anim_time*90*0.5-250)*-9", 0, 0]
},
"neck2": {
"rotation": [30, 0, 0]
"rotation": ["30+math.sin(q.anim_time*90*0.5-260)*5", 0, 2]
}
}
},
"animation.amaura_fetus.quirk": {
"animation_length": 5.16667,
"bones": {
"body": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.7917": {
"post": [5, 0, 0],
"lerp_mode": "catmullrom"
},
"3.125": {
"post": [5, 0, 0],
"lerp_mode": "catmullrom"
},
"4.875": [0, 0, 0]
}
},
"neck": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.375": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [-2, 0, 0],
"lerp_mode": "catmullrom"
},
"2.125": {
"post": [-2, 0, 0],
"lerp_mode": "catmullrom"
},
"2.875": {
"post": [-2, 0, 0],
"lerp_mode": "catmullrom"
},
"3.0833": {
"post": [-0.43, 0, 0],
"lerp_mode": "catmullrom"
},
"4.5": [0, 0, 0]
}
},
"neck2": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.4583": {
"post": [-9, 0, 0],
"lerp_mode": "catmullrom"
},
"2.4583": {
"post": [-9, 0, 0],
"lerp_mode": "catmullrom"
},
"3.125": {
"post": [-9, 0, 0],
"lerp_mode": "catmullrom"
},
"4.125": {
"post": [-2.41, 0, 0],
"lerp_mode": "catmullrom"
},
"4.7917": [0, 0, 0]
}
},
"neck3": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.4583": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"1.5833": {
"post": [-16.1, 0, 0],
"lerp_mode": "catmullrom"
},
"1.8333": {
"post": [-16.92, 0, 0],
"lerp_mode": "catmullrom"
},
"2.0417": {
"post": [-15.66, 0, 0],
"lerp_mode": "catmullrom"
},
"2.2917": {
"post": [-16.09, 0, 0],
"lerp_mode": "catmullrom"
},
"2.625": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"3.2917": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"4.0": {
"post": [-3.53, 0, 0],
"lerp_mode": "catmullrom"
},
"4.75": [0, 0, 0]
}
},
"head": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [-2, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [3, 0, 0],
"lerp_mode": "catmullrom"
},
"1.75": {
"post": [-16.5, 0, 0],
"lerp_mode": "catmullrom"
},
"2.0": {
"post": [-19.11, 0, 0],
"lerp_mode": "catmullrom"
},
"2.1667": {
"post": [-21.48, 0, 0],
"lerp_mode": "catmullrom"
},
"2.3333": {
"post": [-22.29, 0, 0],
"lerp_mode": "catmullrom"
},
"2.5": {
"post": [-23.36, 0, 0],
"lerp_mode": "catmullrom"
},
"2.75": {
"post": [-23.64, 0, 0],
"lerp_mode": "catmullrom"
},
"3.0417": {
"post": [-25.5, 0, 0],
"lerp_mode": "catmullrom"
},
"3.5417": {
"post": [-25.5, 0, 0],
"lerp_mode": "catmullrom"
},
"4.0417": {
"post": [-19.56, 0, 0],
"lerp_mode": "catmullrom"
},
"4.5833": {
"post": [-4.49, 0, 0],
"lerp_mode": "catmullrom"
},
"5.0": [0, 0, 0]
}
},
"fin_right": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.5833": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.25": {
"post": [0, -8, 0],
"lerp_mode": "catmullrom"
},
"2.375": {
"post": [0, -3, 0],
"lerp_mode": "catmullrom"
},
"3.0": {
"post": [0, -1, 0],
"lerp_mode": "catmullrom"
},
"4.1667": {
"post": [0, 5.5, 0],
"lerp_mode": "catmullrom"
},
"4.6667": {
"post": [0, 0.92, 0],
"lerp_mode": "catmullrom"
},
"5.0": [0, 0, 0]
}
},
"fin_left": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.5833": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.25": {
"post": [0, 8, 0],
"lerp_mode": "catmullrom"
},
"2.375": {
"post": [0, 3, 0],
"lerp_mode": "catmullrom"
},
"3.0": {
"post": [0, 1, 0],
"lerp_mode": "catmullrom"
},
"4.1667": {
"post": [0, -5.5, 0],
"lerp_mode": "catmullrom"
},
"4.6667": {
"post": [0, -0.92, 0],
"lerp_mode": "catmullrom"
},
"5.0": [0, 0, 0]
}
},
"leg_front_right": {
"rotation": {
"0.1667": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0": {
"post": [0, -6, 0],
"lerp_mode": "catmullrom"
},
"1.9583": {
"post": [0, 14.25, 0],
"lerp_mode": "catmullrom"
},
"3.4583": {
"post": [0, 19.25, 0],
"lerp_mode": "catmullrom"
},
"4.375": {
"post": [0, 4.46, 0],
"lerp_mode": "catmullrom"
},
"5.1667": [0, 0, 0]
}
},
"leg_front_left": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.8333": {
"post": [0, 6, 0],
"lerp_mode": "catmullrom"
},
"1.7917": {
"post": [0, -14.25, 0],
"lerp_mode": "catmullrom"
},
"3.2917": {
"post": [0, -19.25, 0],
"lerp_mode": "catmullrom"
},
"4.2083": {
"post": [0, -4.46, 0],
"lerp_mode": "catmullrom"
},
"5.0": [0, 0, 0]
}
}
}
}
@@ -5,74 +5,814 @@
"loop": true,
"bones": {
"body": {
"rotation": [15, 0, 0],
"position": [0, 10, 3.5]
"rotation": ["-27.5+math.sin(q.anim_time*90*0.5-180)*3", "math.sin(q.anim_time*90*0.75-60)*-2", "math.sin(q.anim_time*90*1)*1"],
"position": [
"math.sin(q.anim_time*90*0.25)*0.2",
"10+math.sin(q.anim_time*90*0.5-45)*0.8",
"2.5+math.sin(q.anim_time*90*0.25-90)*0.1+math.sin(q.anim_time*90*0.5-90)*0.3"
]
},
"mandible_arm_left": {
"rotation": [-35, -70, 0]
"rotation": ["-35+math.sin(q.anim_time*90*0.5-90)*6", -20, 0],
"position": [0, 0, 0]
},
"mandible_arm_left2": {
"rotation": [70, 0, 0],
"rotation": ["75+math.sin(q.anim_time*90*0.5-90)*12", 0, 0],
"position": [0, 0, 0]
},
"mandible_arm_right": {
"rotation": [-35, 70, 0],
"rotation": ["-35+math.sin(q.anim_time*90*0.5-90)*6", 20, 0],
"position": [0, 0, 0]
},
"mandible_arm_right2": {
"rotation": [70, 0, 0],
"rotation": ["75+math.sin(q.anim_time*90*0.5-90)*12", 0, 0],
"position": [0, 0, 0]
},
"eye_stem_right": {
"rotation": [0, -10, 0]
"rotation": [0, "-10+math.sin(q.anim_time*90*0.5)*-1", 0]
},
"eye_stem_left": {
"rotation": [0, 10, 0]
},
"abdomen": {
"rotation": [0, 0, 0]
"rotation": [0, "10+math.sin(q.anim_time*90*0.5)*1", 0]
},
"wing_right": {
"rotation": [0, 0, -10]
"rotation": [7.5, 0, "-10+math.sin(q.anim_time*90*0.5-250)*7"]
},
"wing_left": {
"rotation": [0, 0, 10]
"rotation": [7.5, 0, "10+math.sin(q.anim_time*90*0.5-250)*-7"]
},
"abdomen2": {
"rotation": [-70, 0, 0]
"rotation": ["-30+math.sin(q.anim_time*90*0.5-210)*2", 0, 0]
},
"wing_right2": {
"rotation": [-10, -2, -15]
"rotation": [-10, -2, "-15+math.sin(q.anim_time*90*0.5-290)*9"]
},
"wing_left2": {
"rotation": [-10, 2, 15]
"rotation": [-10, 2, "15+math.sin(q.anim_time*90*0.5-290)*-9"]
},
"abdomen3": {
"rotation": [-35, 0, 0]
"rotation": ["-35+math.sin(q.anim_time*90*0.5-240)*5", 0, 0]
},
"wing_right3": {
"rotation": [0, 5, -15]
"rotation": [-5, 5, "-15+math.sin(q.anim_time*90*0.5-320)*12"]
},
"wing_left3": {
"rotation": [0, -5, 15]
"rotation": [-5, -5, "15+math.sin(q.anim_time*90*0.5-320)*-12"]
},
"abdomen4": {
"rotation": [-20, 0, 0]
"rotation": ["-20+math.sin(q.anim_time*90*0.5-270)*8", 0, 0]
},
"wing_right4": {
"rotation": [0, 10, -15]
"rotation": [0, 10, "-15+math.sin(q.anim_time*90*0.5-350)*15"]
},
"wing_left4": {
"rotation": [0, -10, 15]
"rotation": [0, -10, "15+math.sin(q.anim_time*90*0.5-350)*-15"]
},
"tail": {
"rotation": [-37, 0, 0]
"rotation": ["-37+math.sin(q.anim_time*90*0.5-300)*12", 0, 0]
},
"right_tail_fin": {
"rotation": [0, 0, 30]
"rotation": [0, 0, "10+math.sin(q.anim_time*90*0.5-20)*25"]
},
"left_tail_fin": {
"rotation": [0, 0, -30]
"rotation": [0, 0, "-10+math.sin(q.anim_time*90*0.5-20)*-25"]
}
}
},
"animation.anorith_fetus.quirk": {
"animation_length": 5.08333,
"bones": {
"abdomen2": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.3333": {
"post": [2.67, 0, 0],
"lerp_mode": "catmullrom"
},
"0.7917": {
"post": [11, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [-6, 0, 0],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [8, 0, 0],
"lerp_mode": "catmullrom"
},
"1.7083": {
"post": [-4, 0, 0],
"lerp_mode": "catmullrom"
},
"2.0417": {
"post": [5, 0, 0],
"lerp_mode": "catmullrom"
},
"2.5": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
},
"3.25": {
"post": [3, 0, 0],
"lerp_mode": "catmullrom"
},
"4.2917": [0, 0, 0]
}
},
"body": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.3333": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [-3, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0": {
"post": [2, 0, 0],
"lerp_mode": "catmullrom"
},
"1.25": {
"post": [-4, 0, 0],
"lerp_mode": "catmullrom"
},
"1.625": {
"post": [1, 0, 0],
"lerp_mode": "catmullrom"
},
"1.9583": {
"post": [-4, 0, 0],
"lerp_mode": "catmullrom"
},
"2.375": {
"post": [-3, 0, 0],
"lerp_mode": "catmullrom"
},
"3.125": {
"post": [-0.7, 0, 0],
"lerp_mode": "catmullrom"
},
"4.0417": [0, 0, 0]
}
},
"mandible_arm_left": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.75": {
"post": [-11, 0, 0],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [9, 0, 0],
"lerp_mode": "catmullrom"
},
"1.6667": {
"post": [-17, 0, 0],
"lerp_mode": "catmullrom"
},
"2.125": {
"post": [14, 0, 0],
"lerp_mode": "catmullrom"
},
"2.875": {
"post": [-6, 0, 0],
"lerp_mode": "catmullrom"
},
"3.75": {
"post": [-1.98, 0, 0],
"lerp_mode": "catmullrom"
},
"4.4583": [0, 0, 0]
}
},
"mandible_arm_left2": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.625": {
"post": [12.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0417": {
"post": [-17.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.4167": {
"post": [7.5, 0, 0],
"lerp_mode": "catmullrom"
},
"2.0": {
"post": [-22.5, 0, 0],
"lerp_mode": "catmullrom"
},
"2.4167": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
},
"3.1667": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"4.125": {
"post": [-3.75, 0, 0],
"lerp_mode": "catmullrom"
},
"4.875": [0, 0, 0]
}
},
"mandible_arm_right": {
"rotation": {
"0.2083": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.9583": {
"post": [-11, 0, 0],
"lerp_mode": "catmullrom"
},
"1.4167": {
"post": [9, 0, 0],
"lerp_mode": "catmullrom"
},
"1.875": {
"post": [-17, 0, 0],
"lerp_mode": "catmullrom"
},
"2.3333": {
"post": [14, 0, 0],
"lerp_mode": "catmullrom"
},
"3.0833": {
"post": [-6, 0, 0],
"lerp_mode": "catmullrom"
},
"3.9583": {
"post": [-1.98, 0, 0],
"lerp_mode": "catmullrom"
},
"4.6667": [0, 0, 0]
}
},
"mandible_arm_right2": {
"rotation": {
"0.2083": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.8333": {
"post": [12.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.25": {
"post": [-17.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.625": {
"post": [7.5, 0, 0],
"lerp_mode": "catmullrom"
},
"2.2083": {
"post": [-22.5, 0, 0],
"lerp_mode": "catmullrom"
},
"2.625": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
},
"3.375": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"4.3333": {
"post": [-3.75, 0, 0],
"lerp_mode": "catmullrom"
},
"5.0833": [0, 0, 0]
}
},
"wing_right": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.7083": {
"post": [0, 0, 4.5],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [0, 0, -10.5],
"lerp_mode": "catmullrom"
},
"1.375": {
"post": [0, 0, 8.5],
"lerp_mode": "catmullrom"
},
"1.625": {
"post": [0, 0, -7],
"lerp_mode": "catmullrom"
},
"1.9583": {
"post": [0, 0, 6],
"lerp_mode": "catmullrom"
},
"2.5417": {
"post": [0, 0, -5],
"lerp_mode": "catmullrom"
},
"3.5": {
"post": [0, 0, -1],
"lerp_mode": "catmullrom"
},
"4.4167": [0, 0, 0]
}
},
"wing_left": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.7083": {
"post": [0, 0, -4.5],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [0, 0, 10.5],
"lerp_mode": "catmullrom"
},
"1.375": {
"post": [0, 0, -8.5],
"lerp_mode": "catmullrom"
},
"1.625": {
"post": [0, 0, 7],
"lerp_mode": "catmullrom"
},
"1.9583": {
"post": [0, 0, -6],
"lerp_mode": "catmullrom"
},
"2.5417": {
"post": [0, 0, 5],
"lerp_mode": "catmullrom"
},
"3.5": {
"post": [0, 0, 1],
"lerp_mode": "catmullrom"
},
"4.4167": [0, 0, 0]
}
},
"wing_right2": {
"rotation": {
"0.1667": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.875": {
"post": [0, 0, 4.5],
"lerp_mode": "catmullrom"
},
"1.25": {
"post": [0, 0, -10.5],
"lerp_mode": "catmullrom"
},
"1.5417": {
"post": [0, 0, 8.5],
"lerp_mode": "catmullrom"
},
"1.7917": {
"post": [0, 0, -7],
"lerp_mode": "catmullrom"
},
"2.125": {
"post": [0, 0, 6],
"lerp_mode": "catmullrom"
},
"2.7083": {
"post": [0, 0, -5],
"lerp_mode": "catmullrom"
},
"3.6667": {
"post": [0, 0, -1],
"lerp_mode": "catmullrom"
},
"4.5833": [0, 0, 0]
}
},
"wing_left2": {
"rotation": {
"0.1667": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.875": {
"post": [0, 0, -4.5],
"lerp_mode": "catmullrom"
},
"1.25": {
"post": [0, 0, 10.5],
"lerp_mode": "catmullrom"
},
"1.5417": {
"post": [0, 0, -8.5],
"lerp_mode": "catmullrom"
},
"1.7917": {
"post": [0, 0, 7],
"lerp_mode": "catmullrom"
},
"2.125": {
"post": [0, 0, -6],
"lerp_mode": "catmullrom"
},
"2.7083": {
"post": [0, 0, 5],
"lerp_mode": "catmullrom"
},
"3.6667": {
"post": [0, 0, 1],
"lerp_mode": "catmullrom"
},
"4.5833": [0, 0, 0]
}
},
"abdomen3": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [-3, 0, 0],
"lerp_mode": "catmullrom"
},
"0.9583": {
"post": [10, 0, 0],
"lerp_mode": "catmullrom"
},
"1.25": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
},
"1.5417": {
"post": [9, 0, 0],
"lerp_mode": "catmullrom"
},
"1.875": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"2.3333": {
"post": [7, 0, 0],
"lerp_mode": "catmullrom"
},
"2.75": {
"post": [2, 0, 0],
"lerp_mode": "catmullrom"
},
"3.5": {
"post": [2, 0, 0],
"lerp_mode": "catmullrom"
},
"4.5": [0, 0, 0]
}
},
"wing_right3": {
"rotation": {
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.9583": {
"post": [0, 0, 4.5],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [0, 0, -10.5],
"lerp_mode": "catmullrom"
},
"1.625": {
"post": [0, 0, 8.5],
"lerp_mode": "catmullrom"
},
"1.875": {
"post": [0, 0, -7],
"lerp_mode": "catmullrom"
},
"2.2083": {
"post": [0, 0, 6],
"lerp_mode": "catmullrom"
},
"2.7917": {
"post": [0, 0, -5],
"lerp_mode": "catmullrom"
},
"3.75": {
"post": [0, 0, -1],
"lerp_mode": "catmullrom"
},
"4.6667": [0, 0, 0]
}
},
"wing_left3": {
"rotation": {
"0.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.9583": {
"post": [0, 0, -4.5],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [0, 0, 10.5],
"lerp_mode": "catmullrom"
},
"1.625": {
"post": [0, 0, -8.5],
"lerp_mode": "catmullrom"
},
"1.875": {
"post": [0, 0, 7],
"lerp_mode": "catmullrom"
},
"2.2083": {
"post": [0, 0, -6],
"lerp_mode": "catmullrom"
},
"2.7917": {
"post": [0, 0, 5],
"lerp_mode": "catmullrom"
},
"3.75": {
"post": [0, 0, 1],
"lerp_mode": "catmullrom"
},
"4.6667": [0, 0, 0]
}
},
"abdomen4": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.75": {
"post": [-8, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0417": {
"post": [7, 0, 0],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [-11, 0, 0],
"lerp_mode": "catmullrom"
},
"1.625": {
"post": [5, 0, 0],
"lerp_mode": "catmullrom"
},
"2.0": {
"post": [-7, 0, 0],
"lerp_mode": "catmullrom"
},
"2.4583": {
"post": [4, 0, 0],
"lerp_mode": "catmullrom"
},
"3.0417": {
"post": [-3, 0, 0],
"lerp_mode": "catmullrom"
},
"4.0833": {
"post": [2, 0, 0],
"lerp_mode": "catmullrom"
},
"4.9167": [0, 0, 0]
}
},
"wing_right4": {
"rotation": {
"0.375": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [0, 0, 4.5],
"lerp_mode": "catmullrom"
},
"1.4583": {
"post": [0, 0, -10.5],
"lerp_mode": "catmullrom"
},
"1.75": {
"post": [0, 0, 8.5],
"lerp_mode": "catmullrom"
},
"2.0": {
"post": [0, 0, -7],
"lerp_mode": "catmullrom"
},
"2.3333": {
"post": [0, 0, 6],
"lerp_mode": "catmullrom"
},
"2.9167": {
"post": [0, 0, -5],
"lerp_mode": "catmullrom"
},
"3.875": {
"post": [0, 0, -1],
"lerp_mode": "catmullrom"
},
"4.7917": [0, 0, 0]
}
},
"wing_left4": {
"rotation": {
"0.375": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [0, 0, -4.5],
"lerp_mode": "catmullrom"
},
"1.4583": {
"post": [0, 0, 10.5],
"lerp_mode": "catmullrom"
},
"1.75": {
"post": [0, 0, -8.5],
"lerp_mode": "catmullrom"
},
"2.0": {
"post": [0, 0, 7],
"lerp_mode": "catmullrom"
},
"2.3333": {
"post": [0, 0, -6],
"lerp_mode": "catmullrom"
},
"2.9167": {
"post": [0, 0, 5],
"lerp_mode": "catmullrom"
},
"3.875": {
"post": [0, 0, 1],
"lerp_mode": "catmullrom"
},
"4.7917": [0, 0, 0]
}
},
"tail": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.4583": {
"post": [-15, 0, 0],
"lerp_mode": "catmullrom"
},
"0.8333": {
"post": [-17.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.125": {
"post": [7.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.375": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.6667": {
"post": [12.5, 0, 0],
"lerp_mode": "catmullrom"
},
"2.0833": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"2.5": {
"post": [15, 0, 0],
"lerp_mode": "catmullrom"
},
"3.125": {
"post": [-5, 0, 0],
"lerp_mode": "catmullrom"
},
"4.2917": {
"post": [7.5, 0, 0],
"lerp_mode": "catmullrom"
},
"5.0833": [0, 0, 0]
}
},
"right_tail_fin": {
"rotation": {
"0.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [0, 0, -4.5],
"lerp_mode": "catmullrom"
},
"1.5833": {
"post": [0, 0, 10.5],
"lerp_mode": "catmullrom"
},
"1.875": {
"post": [0, 0, -8.5],
"lerp_mode": "catmullrom"
},
"2.125": {
"post": [0, 0, 7],
"lerp_mode": "catmullrom"
},
"2.4583": {
"post": [0, 0, -6],
"lerp_mode": "catmullrom"
},
"3.0417": {
"post": [0, 0, 5],
"lerp_mode": "catmullrom"
},
"4.0": {
"post": [0, 0, 1],
"lerp_mode": "catmullrom"
},
"4.9167": [0, 0, 0]
}
},
"left_tail_fin": {
"rotation": {
"0.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [0, 0, 4.5],
"lerp_mode": "catmullrom"
},
"1.5833": {
"post": [0, 0, -10.5],
"lerp_mode": "catmullrom"
},
"1.875": {
"post": [0, 0, 8.5],
"lerp_mode": "catmullrom"
},
"2.125": {
"post": [0, 0, -7],
"lerp_mode": "catmullrom"
},
"2.4583": {
"post": [0, 0, 6],
"lerp_mode": "catmullrom"
},
"3.0417": {
"post": [0, 0, -5],
"lerp_mode": "catmullrom"
},
"4.0": {
"post": [0, 0, -1],
"lerp_mode": "catmullrom"
},
"4.9167": [0, 0, 0]
}
}
}
}

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