Compare commits

..
Author SHA1 Message Date
whatsy b6beed0963 cleanup 2026-11-03 10:27:13 -05:00
Ronak Chavva 2a882e137a fix(*): temp feature individualism 2026-11-02 13:34:52 -06:00
whatsy 9be710ff32 this floette is gonna drive me insane 2026-11-02 10:57:44 -05:00
whatsy 7a9393b39f more pokedex compat and other stuff 2026-11-01 15:12:12 -05:00
whatsy 087a167bfa ...and then make that PlatformRegistry actually work 2026-10-30 15:18:54 -04:00
whatsy 461d21a87d Convert CobblemonLootItemConditions into a PlatformRegistry 2026-10-30 14:48:30 -04:00
whatsy 78953357a8 Pokedex compat 2026-10-30 14:39:38 -04:00
whatsy bdfabb3724 Update CHANGELOG.md + resolve merge conflicts 2026-10-27 23:54:56 -04:00
whatsy 3adb6144a3 Merge branch 'refs/heads/main' into drop-system-update
# Conflicts:
#	common/src/main/resources/data/cobblemon/species/generation1/exeggutor.json
#	common/src/main/resources/data/cobblemon/species/generation4/rotom.json
#	common/src/main/resources/data/cobblemon/species/generation4/wormadam.json
#	common/src/main/resources/data/cobblemon/species/generation5/kyurem.json
#	common/src/main/resources/data/cobblemon/species/generation6/avalugg.json
#	common/src/main/resources/data/cobblemon/species/generation6/flabebe.json
#	common/src/main/resources/data/cobblemon/species/generation6/floette.json
#	common/src/main/resources/data/cobblemon/species/generation6/florges.json
#	common/src/main/resources/data/cobblemon/species/generation6/goodra.json
#	common/src/main/resources/data/cobblemon/species/generation6/greninja.json
#	common/src/main/resources/data/cobblemon/species/generation6/sliggoo.json
#	common/src/main/resources/data/cobblemon/species/generation7/decidueye.json
#	common/src/main/resources/data/cobblemon/species/generation8/toxtricity.json
2026-10-27 23:48:49 -04:00
whatsy 65bcd118a3 finalizing 2026-10-21 13:25:46 -04:00
whatsy bf6f97e740 auto fire aspect support 2026-10-21 12:25:24 -04:00
whatsy 4e48e2ff9b scraper updates 2026-10-20 18:43:01 -04:00
whatsy faa488b153 ported all pokemon over to loot tables 2026-10-19 17:09:20 -04:00
whatsy 93dbc015fb loot table drop entry type implementation 2026-10-19 13:49:34 -04:00
whatsy 7edf6669d8 Vanilla loot tables for pokemon drops: wip, pushing for review 2026-10-19 11:52:44 -04:00
2770 changed files with 96901 additions and 20734 deletions

No files matched your search

+15 -25
View File
@@ -1,37 +1,27 @@
# Changelog
## [1.9.0 (MONTH xth, 2026)](#1-9-0)
## [1.8.5 (MONTH xth, 2026)](#1-8-5)
### Additions
- Trainer bags and packs got added
- You can craft and equip those to store additional items
### Particles
### Cries added/updated for the following Pokémon
### Model updates for the following Pokémon
### Animation updates for the following Pokémon
### Changes
- Trading has been overhauled to allow offering multiple Pokémon, up to the entire party, in a single trade
- Selected Pokémon are now highlighted in both parties with new party slot assets
- Hovering an offered Pokémon now shows its summary, and clicking the active Pokémon no longer exits the summary view
- The trade animation now moves the offered Pokémon towards the Poké Ball
- Parties are compacted after a trade so no empty slots are left between Pokémon
### Fixes
### Developer
- Trade network packets (`TradeUpdatedPacket`, `UpdateTradeOfferPacket`, and `TradeCompletedPacket`) now receive an array of Pokémon instead of a single Pokémon to execute trades
- `TradeEvent.Pre` and `TradeEvent.Post` now expose every Pokémon each participant receives (`tradeParticipant1Pokemon` and `tradeParticipant2Pokemon` are now lists), and their Molang context includes `trade_participant_1_pokemon_list` and `trade_participant_2_pokemon_list`
### Molang & Datapacks
- `bag_categories` got added which control what kind of tabs and capabilities the Trainerbags have
```json
{
"order": 1,
"icon": "cobblemon:textures/item/medicine/potion.png",
"whiteListTag": "cobblemon:bag/whitelist_consumables",
"blackListTag": "cobblemon:bag/blacklist_consumables",
"maxCount": 512
}
```
- Bunch of default tags as white/blacklist got added to control what can be inserted the corresponding bag categories
- Added a `loot_table` drop entry type.
- Accepts an `id` field, pointing to a vanilla loot table.
- All base mod Pokémon have been moved to this new system.
- Added the `cobblemon:requirement` loot item condition.
- Accepts a `requirement` field, containing a Requirement, using the existing Cobblemon requirement system.
### Particles
### Localization
- Updated translations for:
### Localization
@@ -1,16 +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.bag;
import com.cobblemon.mod.common.item.bag.CobblemonBagContainer;
public interface BagEntity {
CobblemonBagContainer cobblemon$getBagContainer();
void cobblemon$setBagContainer(CobblemonBagContainer bagContainer);
}
@@ -23,8 +23,6 @@ import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.duck.PlayerDuck;
import com.cobblemon.mod.common.duck.RidePassenger;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.bag.BagEntity;
import com.cobblemon.mod.common.item.bag.CobblemonBagContainer;
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
import com.cobblemon.mod.common.pokemon.FormData;
@@ -58,7 +56,6 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import org.objectweb.asm.Opcodes;
@@ -76,7 +73,7 @@ import java.util.*;
import java.util.stream.Collectors;
@Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger, BagEntity {
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
@Unique
private Vector3f cobblemon$driverInput;
@@ -110,8 +107,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
@Unique private Vec3 cobblemon$rideEyePos = Vec3.ZERO;
@Unique private CobblemonBagContainer cobblemon$cobblemonBagContainer = new CobblemonBagContainer();
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
super(p_20966_, p_20967_);
}
@@ -409,37 +404,4 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
original.call(target, strength, x, z);
}
@Override @NotNull
public CobblemonBagContainer cobblemon$getBagContainer() { return cobblemon$cobblemonBagContainer; }
@Override
public void cobblemon$setBagContainer(CobblemonBagContainer bagContainer) { cobblemon$cobblemonBagContainer = bagContainer; }
@Inject(
method = "readAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V",
at = @At("TAIL")
)
private void cobblemon$readAdditionalSaveData(CompoundTag compound, CallbackInfo ci) {
if (compound.contains("CobblemonBagData", 9)) {
this.cobblemon$cobblemonBagContainer.fromTag(compound.getList("CobblemonBagData", 10), this.registryAccess());
}
}
@Inject(
method = "addAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V",
at = @At("TAIL")
)
private void cobblemon$addAdditionalSaveData(CompoundTag compound, CallbackInfo ci) {
compound.put("CobblemonBagData", this.cobblemon$cobblemonBagContainer.createTag(this.registryAccess()));
}
@Inject(
method = "dropEquipment()V",
at = @At("TAIL")
)
private void cobblemon$dropCobblemonBag(CallbackInfo ci) {
if (level().getGameRules().getBoolean(CobblemonGameRules.BAG_DROP_ITEMS)) {
this.cobblemon$cobblemonBagContainer.dropAll((Player)(Object)this);
}
}
}
@@ -15,23 +15,17 @@ import com.cobblemon.mod.common.api.riding.RidingStyle;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
import com.cobblemon.mod.common.api.stats.CobblemonStats;
import com.cobblemon.mod.common.block.HealingMachineBlock;
import com.cobblemon.mod.common.duck.ServerLevelDuck;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.bag.BagEntity;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -39,9 +33,6 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Optional;
@Mixin(ServerPlayer.class)
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
@@ -151,25 +142,4 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
((ServerLevelDuck) this.serverLevel()).cobblemon$getLevelResourceLocation()
);
}
@Inject(
method = "findRespawnAndUseSpawnBlock(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;FZZ)Ljava/util/Optional;",
at = @At(value = "HEAD"),
cancellable = true
)
private static void cobblemon$useHealthStationAsRespawn(ServerLevel level, BlockPos pos, float angle, boolean forced, boolean keepInventory, CallbackInfoReturnable<Optional<ServerPlayer.RespawnPosAngle>> cir) {
BlockState state = level.getBlockState(pos);
Block block = state.getBlock();
if (block instanceof HealingMachineBlock && HealingMachineBlock.Companion.canSetSpawn(level)) {
cir.setReturnValue(HealingMachineBlock.Companion.findStandUpPosition(EntityType.PLAYER, level, pos).map((vec3) -> ServerPlayer.RespawnPosAngle.of(vec3, pos)));
}
}
@Inject(
method = "restoreFrom",
at = @At("TAIL")
)
private void cobblemon$restoreCobblemonBag(ServerPlayer that, boolean keepEverything, CallbackInfo ci) {
((BagEntity)(Object)this).cobblemon$setBagContainer(((BagEntity)that).cobblemon$getBagContainer());
}
}
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.drop.CommandDropEntry
import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.drop.EvolutionItemDropEntry
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.drop.LootTableDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.habitats.HabitatPools
@@ -90,6 +91,7 @@ import com.cobblemon.mod.common.events.EntityCallbackHandler
import com.cobblemon.mod.common.events.PokedexHandler
import com.cobblemon.mod.common.events.ServerTickHandler
import com.cobblemon.mod.common.events.StatHandler
import com.cobblemon.mod.common.loot.CobblemonLootItemConditions
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.permission.LaxPermissionValidator
import com.cobblemon.mod.common.platform.events.PlatformEvents
@@ -223,12 +225,15 @@ object Cobblemon {
implementation.registerEntityDataSerializers()
implementation.registerCriteria()
implementation.registerEntitySubPredicates()
implementation.registerLootItemConditions()
implementation.registerMobEffects()
DispenserBehaviorRegistry.registerDispenserBehaviors()
CobblemonLootItemConditions.touch()
DropEntry.register("command", CommandDropEntry::class.java)
DropEntry.register("item", ItemDropEntry::class.java, isDefault = true)
DropEntry.register("evolution", EvolutionItemDropEntry::class.java)
DropEntry.register("loot_table", LootTableDropEntry::class.java)
ExperienceGroups.registerDefaults()
CaptureCalculators.registerDefaults()
@@ -118,6 +118,7 @@ interface CobblemonImplementation {
fun registerMenu()
fun registerEntitySubPredicates()
fun registerLootItemConditions()
/**
* TODO
@@ -26,7 +26,6 @@ import com.cobblemon.mod.common.client.pokedex.PokedexType
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.*
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
import com.cobblemon.mod.common.item.bag.CobblemonBagItem
import com.cobblemon.mod.common.item.battle.DireHitItem
import com.cobblemon.mod.common.item.battle.GuardSpecItem
import com.cobblemon.mod.common.item.battle.XStatItem
@@ -1578,12 +1577,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val LUCIBELL = compostableBlockItem("lucibell", CobblemonBlocks.LUCIBELL, 0.85f)
//Bags
@JvmField
val TRAINER_BAG = this.create("trainer_bag", CobblemonBagItem())
@JvmField
val TRAINER_PACK = this.create("trainer_pack", CobblemonBagItem())
private fun blockItem(name: String, block: Block, rarity: Rarity = Rarity.COMMON): BlockItem = this.create(name, BlockItem(block, Item.Properties().rarity(rarity)))
private fun itemNameBlockItem(name: String, block: Block, rarity: Rarity = Rarity.COMMON): ItemNameBlockItem = this.create(name, ItemNameBlockItem(block, Item.Properties().rarity(rarity)))
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.item.bag.CobblemonBagMenu
import com.cobblemon.mod.common.block.tmmachine.TMMachineMenu
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
@@ -21,9 +20,8 @@ import net.minecraft.world.inventory.MenuType
object CobblemonMenuType : PlatformRegistry<Registry<MenuType<*>>, ResourceKey<Registry<MenuType<*>>>, MenuType<*>>() {
val COOKING_POT = MenuType.register("cooking_pot", ::CookingPotMenu)
val COOKING_POT = MenuType.register("cooking_pot_menu", ::CookingPotMenu)
val TM_MACHINE = MenuType.register("tm_machine_menu", ::TMMachineMenu)
val COBBLEMON_BAG = MenuType.register("cobblemon_bag", ::CobblemonBagMenu)
override val registry: Registry<MenuType<*>>
get() = BuiltInRegistries.MENU
@@ -13,8 +13,6 @@ import com.cobblemon.mod.common.client.net.OpenBehaviourEditorHandler
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
import com.cobblemon.mod.common.client.net.animation.PlayPosableAnimationHandler
import com.cobblemon.mod.common.client.net.bag.UpdateBagMenuDataHandler
import com.cobblemon.mod.common.client.net.bag.UseItemOnPokemonFromBagHandler
import com.cobblemon.mod.common.client.net.battle.*
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
@@ -78,8 +76,6 @@ import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
import com.cobblemon.mod.common.net.messages.client.bag.UpdateBagMenuDataPacket
import com.cobblemon.mod.common.net.messages.client.bag.UseItemOnPokemonFromBagPacket
import com.cobblemon.mod.common.net.messages.client.battle.*
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
@@ -448,7 +444,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
list.add(PacketRegisterInfo(BagCategoriesSyncPacket.ID, BagCategoriesSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
@@ -645,10 +640,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(SetActiveTMPacket.ID, SetActiveTMPacket::decode, SetActiveTMPacketHandler))
list.add(PacketRegisterInfo(SetTMMachineContainerDataPacket.ID, SetTMMachineContainerDataPacket::decode, SetTMMachineContainerDataPacketHandler))
// Bag
list.add(PacketRegisterInfo(UpdateBagMenuDataPacket.ID, UpdateBagMenuDataPacket::decode, UpdateBagMenuDataHandler))
list.add(PacketRegisterInfo(UseItemOnPokemonFromBagPacket.ID, UseItemOnPokemonFromBagPacket::decode, UseItemOnPokemonFromBagHandler))
// Behaviour Packets
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
list.add(PacketRegisterInfo(DamageOnCollisionPacket.ID, DamageOnCollisionPacket::decode, DamageOnCollisionPacketHandler))
@@ -656,7 +647,7 @@ object CobblemonNetwork {
// Habitat blocks
list.add(PacketRegisterInfo(SaveHabitatBlockSettingsPacket.ID, SaveHabitatBlockSettingsPacket::decode, SaveHabitatBlockSettingsHandler))
// Debug
// Debug / cheats
list.add(PacketRegisterInfo(RequestOpenRidingStatsDebugGUIPacket.ID, RequestOpenRidingStatsDebugGUIPacket::decode, RequestOpenRidingStatsDebugGUIHandler))
@@ -321,19 +321,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val MEDICINAL_LEEK_PLACE = this.create("block.medicinal_leek.plant")
@JvmField
val ITEM_BAG_OPEN = this.create("item.bag.open")
@JvmField
val ITEM_BAG_CLOSE = this.create("item.bag.close")
@JvmField
val ITEM_BAG_CLICK = this.create("item.bag.click")
@JvmField
val ITEM_BAG_ITEM_IN = this.create("item.bag.item_in")
@JvmField
val ITEM_BAG_ITEM_OUT = this.create("item.bag.item_out")
@JvmField
val ITEM_BAG_EQUIP = this.create("item.bag.equip")
@JvmField
val GILDED_CHEST_OPEN = this.create("block.gilded_chest.open")
@JvmField
@@ -1,66 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.bag
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.BagCategoriesSyncPacket
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.TagKeyAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item
object BagCategories: JsonDataRegistry<BagCategory> {
override val id: ResourceLocation = cobblemonResource("bag_categories")
override val type: PackType = PackType.SERVER_DATA
override val observable = SimpleObservable<BagCategories>()
override val gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(TypeToken.getParameterized(TagKey::class.java, Item::class.java).type, TagKeyAdapter(Registries.ITEM))
.create()
override val typeToken: TypeToken<BagCategory> = TypeToken.get(BagCategory::class.java)
override val resourcePath = "bag_categories"
private val bagCategories = hashMapOf<ResourceLocation, BagCategory>()
override fun reload(data: Map<ResourceLocation, BagCategory>) {
bagCategories.clear()
data.forEach { identifier, category ->
try {
category.identifier = identifier
bagCategories[identifier] = category
} catch (e: Exception) {
Cobblemon.LOGGER.error("Skipped loading the {} category", identifier, e)
}
}
Cobblemon.LOGGER.info("Loaded {} bag categories", bagCategories.size)
this.observable.emit(this)
}
override fun sync(player: ServerPlayer) {
BagCategoriesSyncPacket(bagCategories.values.toList())
}
fun getOrderedCategoriesList(): List<BagCategory> {
return bagCategories.values.toList().sortedBy { it.order }
}
}
@@ -1,66 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.bag
import com.cobblemon.mod.common.util.readIdentifier
import com.cobblemon.mod.common.util.writeIdentifier
import net.minecraft.core.registries.Registries
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.util.StringRepresentable
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
class BagCategory(
identifier: ResourceLocation,
val order: Int,
val icon: ResourceLocation,
val whiteListTag: TagKey<Item>,
val blackListTag: TagKey<Item>,
val maxCount: Int
): StringRepresentable {
@Transient
var identifier: ResourceLocation = identifier
internal set
override fun getSerializedName(): String = identifier.toString()
fun getName(): MutableComponent = Component.translatable("${identifier.namespace}.bag_category.${identifier.path}")
fun itemIsValid(itemStack: ItemStack): Boolean {
if (itemStack.`is`(blackListTag)) return false
if (itemStack.`is`(whiteListTag)) return true
return false
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeIdentifier(identifier)
buffer.writeInt(order)
buffer.writeIdentifier(icon)
buffer.writeIdentifier(whiteListTag.location)
buffer.writeIdentifier(blackListTag.location)
buffer.writeInt(maxCount)
}
companion object {
internal fun decode(buffer: RegistryFriendlyByteBuf): BagCategory {
return BagCategory(
buffer.readIdentifier(),
buffer.readInt(),
buffer.readIdentifier(),
TagKey.create(Registries.ITEM, buffer.readIdentifier()),
TagKey.create(Registries.ITEM, buffer.readIdentifier()),
buffer.readInt()
)
}
}
}
@@ -10,9 +10,14 @@ 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 com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.registries.Registries
import kotlin.random.Random
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
@@ -105,7 +110,11 @@ class DropTable {
) {
LOOT_DROPPED.postThen(
event = LootDroppedEvent(this, player, entity, drops),
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
ifSucceeded = {
val pokemon = (entity as? PokemonEntity)?.pokemon?.species?.resourceIdentifier ?: return@postThen
it.drops.forEach { it.drop(entity, world, pos, player) }
// val lootKey = ResourceKey.create(Registries.LOOT_TABLE, cobblemonResource("pokemon/${pokemon}"))
}
)
}
@@ -0,0 +1,64 @@
package com.cobblemon.mod.common.api.drop
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.phys.Vec3
/**
* A drop entry that points to a vanilla loot table.
*/
class LootTableDropEntry(
override var percentage: Float,
override var quantity: Int,
override var maxSelectableTimes: Int,
val id: ResourceLocation
) : DropEntry {
override fun drop(
entity: LivingEntity?,
world: ServerLevel,
pos: Vec3,
player: ServerPlayer?
) {
val key = ResourceKey.create(Registries.LOOT_TABLE, id)
val playerEntity = player as? LivingEntity
if (entity == null) return
if (playerEntity != null) {
val params = LootParams.Builder(world)
.withParameter(LootContextParams.ATTACKING_ENTITY, playerEntity)
.withParameter(LootContextParams.DAMAGE_SOURCE, playerEntity.damageSources().genericKill())
.withParameter(LootContextParams.ORIGIN, pos)
.withParameter(LootContextParams.THIS_ENTITY, entity)
.create(LootContextParamSets.ENTITY)
val drops = world.server.reloadableRegistries().getLootTable(key)
.getRandomItems(params)
for (stack in drops) {
if (stack.isEmpty) continue
val itemEntity = ItemEntity(world, pos.x, pos.y, pos.z, stack)
itemEntity.setDefaultPickUpDelay()
world.addFreshEntity(itemEntity)
}
} else {
val params = LootParams.Builder(world)
.create(LootContextParamSets.EMPTY)
val drops = world.server.reloadableRegistries().getLootTable(key)
.getRandomItems(params)
for (stack in drops) {
if (stack.isEmpty) continue
val itemEntity = ItemEntity(world, pos.x, pos.y, pos.z, stack)
itemEntity.setDefaultPickUpDelay()
world.addFreshEntity(itemEntity)
}
}
}
}
@@ -9,14 +9,12 @@
package com.cobblemon.mod.common.api.events.pokemon
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.trade.TradeParticipant
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.getPlayer
/**
@@ -33,9 +31,9 @@ interface TradeEvent {
val tradeParticipant1: TradeParticipant
/**
* All the [Pokemon] the first participant receives in the trade.
* The [Pokemon] being traded by the first participant.
*/
val tradeParticipant1Pokemon: List<Pokemon>
val tradeParticipant1Pokemon: Pokemon
/**
* The second [TradeParticipant].
@@ -43,19 +41,9 @@ interface TradeEvent {
val tradeParticipant2: TradeParticipant
/**
* All the [Pokemon] the second participant receives in the trade.
* The [Pokemon] being traded by the second participant.
*/
val tradeParticipant2Pokemon: List<Pokemon>
fun createContext(): MutableMap<String, MoValue> = mutableMapOf(
"trade_participant_1" to (tradeParticipant1.uuid.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
"trade_participant_2" to (tradeParticipant2.uuid.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
// Kept for backwards compatibility, this is the first Pokémon of each side.
"trade_participant_1_pokemon" to tradeParticipant1Pokemon.first().struct,
"trade_participant_2_pokemon" to tradeParticipant2Pokemon.first().struct,
"trade_participant_1_pokemon_list" to tradeParticipant1Pokemon.asArrayValue { it.struct },
"trade_participant_2_pokemon_list" to tradeParticipant2Pokemon.asArrayValue { it.struct }
)
val tradeParticipant2Pokemon: Pokemon
/**
* Event fired when a trade is about to happen. Cancelling this event prevents the trade from occurring.
@@ -65,11 +53,16 @@ interface TradeEvent {
*/
data class Pre(
override val tradeParticipant1: TradeParticipant,
override val tradeParticipant1Pokemon: List<Pokemon>,
override val tradeParticipant1Pokemon: Pokemon,
override val tradeParticipant2: TradeParticipant,
override val tradeParticipant2Pokemon: List<Pokemon>
override val tradeParticipant2Pokemon: Pokemon
) : TradeEvent, Cancelable() {
val context = createContext()
val context = mutableMapOf(
"trade_participant_1" to (tradeParticipant1.uuid.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
"trade_participant_2" to (tradeParticipant2.uuid.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
"trade_participant_1_pokemon" to tradeParticipant1Pokemon.struct,
"trade_participant_2_pokemon" to tradeParticipant2Pokemon.struct
)
val functions = moLangFunctionMap(
cancelFunc
@@ -84,10 +77,15 @@ interface TradeEvent {
*/
data class Post(
override val tradeParticipant1: TradeParticipant,
override val tradeParticipant1Pokemon: List<Pokemon>,
override val tradeParticipant1Pokemon: Pokemon,
override val tradeParticipant2: TradeParticipant,
override val tradeParticipant2Pokemon: List<Pokemon>
override val tradeParticipant2Pokemon: Pokemon
) : TradeEvent {
val context = createContext()
val context = mutableMapOf(
"trade_participant_1" to (tradeParticipant1.uuid.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
"trade_participant_2" to (tradeParticipant2.uuid.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
"trade_participant_1_pokemon" to tradeParticipant1Pokemon.struct,
"trade_participant_2_pokemon" to tradeParticipant2Pokemon.struct
)
}
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.pokedex.filter
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.drop.LootTableDropEntry
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
@@ -17,14 +18,22 @@ import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.api.tms.TechnicalMachines
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.pokedex.widgets.DropsScrollingWidget.DropWidgetEntry
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.itemRegistry
import com.cobblemon.mod.common.util.server
import com.google.gson.JsonArray
import com.google.gson.JsonParser
import net.minecraft.client.Minecraft
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.world.item.ItemStack
import java.util.Locale
import java.util.Locale.getDefault
/**
* A Pokedex [EntryFilter] that filters out entries that do not contain the current search.
@@ -75,11 +84,59 @@ class SearchFilter(val pokedexManager: AbstractPokedexManager, val searchString:
if (pokedexManager.getHighestKnowledgeFor(entry) == PokedexEntryProgress.UNREGISTERED) return false
val dropsList = mutableListOf<String>()
val formsList = if (species.forms.isEmpty()) mutableListOf(species.standardForm) else species.forms
formsList.forEach {
it.drops.entries.forEach {
if (it is ItemDropEntry) {
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(it.item)?.defaultInstance ?: ItemStack.EMPTY
formsList.forEach { formData ->
formData.drops.entries.forEach { dropEntry ->
if (dropEntry is ItemDropEntry) {
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(dropEntry.item)?.defaultInstance ?: ItemStack.EMPTY
if (!itemStack.isEmpty) dropsList.add(itemStack.displayName.string.lowercase())
} else if (dropEntry is LootTableDropEntry) {
val server = server() ?: return@forEach
val lootTableResource = ResourceLocation.fromNamespaceAndPath(
dropEntry.id.namespace,
"loot_table/${dropEntry.id.path}.json"
)
val resource = server.resourceManager
.getResource(lootTableResource)
.orElse(null)
?: return@forEach
val json = resource.openAsReader().use { reader ->
JsonParser.parseReader(reader).asJsonObject
}
json.getAsJsonArray("pools")?.forEach { poolElement ->
val pool = poolElement.asJsonObject
val entries = pool.getAsJsonArray("entries") ?: return@forEach
for (entry in entries.map { it.asJsonObject }) {
val items = mutableSetOf<String>()
if (entry["type"].asString == "minecraft:tag") {
val itemRegistry = Minecraft.getInstance()
.level!!
.registryAccess()
.lookupOrThrow(Registries.ITEM)
val tagKey = TagKey.create(Registries.ITEM, ResourceLocation.parse(entry["name"].asString))
val tagItems = itemRegistry.getOrThrow(tagKey)
.stream()
.map { holder ->
holder.unwrapKey().map {
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(it.location())?.defaultInstance ?: ItemStack.EMPTY
itemStack.displayName.string.lowercase()
}.orElse(null)
}.toList().filterNotNull()
items.addAll(tagItems)
} else if (entry["type"].asString == "minecraft:item") {
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(ResourceLocation.parse(entry["name"].asString))?.defaultInstance ?: ItemStack.EMPTY
items.add(itemStack.displayName.string.lowercase())
}
dropsList.addAll(items.map { it })
}
}
}
}
}
@@ -8,9 +8,14 @@
package com.cobblemon.mod.common.api.pokemon.requirement
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.evolution.ContextEvolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.Dynamic
import com.mojang.serialization.JsonOps
import net.minecraft.resources.ResourceLocation
import java.util.WeakHashMap
@@ -40,5 +45,26 @@ fun interface Requirement {
companion object {
val pokedexIconOverrides = WeakHashMap<Requirement, ResourceLocation>()
val pokedexTooltipOverrides = WeakHashMap<Requirement, String>()
val CODEC: Codec<Requirement> = Codec.PASSTHROUGH.comapFlatMap(
{ dynamic ->
try {
val json = dynamic.convert(JsonOps.INSTANCE).value
DataResult.success(
PokemonSpecies.gson.fromJson(json, Requirement::class.java)
)
} catch (e: Exception) {
DataResult.error {
"Failed to decode Requirement: ${e.message}"
}
}
},
{ requirement ->
Dynamic(
JsonOps.INSTANCE,
PokemonSpecies.gson.toJsonTree(requirement, Requirement::class.java)
)
}
)
}
}
@@ -140,20 +140,6 @@ object CobblemonItemTags {
@JvmField val WEARABLE_HAT_ITEMS = create("held/visibility/hat")
@JvmField val HIDDEN_ITEMS = create("held/visibility/hidden")
//Bag Categories Tags
@JvmField val BAG_WHITELIST_POKE_BALLS = create("bag/whitelist_poke_balls")
@JvmField val BAG_BLACKLIST_POKE_BALLS = create("bag/blacklist_poke_balls")
@JvmField val BAG_WHITELIST_CONSUMABLES = create("bag/whitelist_consumables")
@JvmField val BAG_BLACKLIST_CONSUMABLES = create("bag/blacklist_consumables")
@JvmField val BAG_WHITELIST_BERRIES = create("bag/whitelist_berries")
@JvmField val BAG_BLACKLIST_BERRIES = create("bag/blacklist_berries")
@JvmField val BAG_WHITELIST_HELD_EVO = create("bag/whitelist_held_evo")
@JvmField val BAG_BLACKLIST_HELD_EVO = create("bag/blacklist_held_evo")
@JvmField val BAG_WHITELIST_CURRENCY = create("bag/whitelist_currency")
@JvmField val BAG_BLACKLIST_CURRENCY = create("bag/blacklist_currency")
@JvmField val BAG_WHITELIST_TMS = create("bag/whitelist_tms")
@JvmField val BAG_BLACKLIST_TMS = create("bag/blacklist_tms")
//Empty Tag
@JvmField val EMPTY = create("empty")
@@ -24,7 +24,6 @@ import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.util.RandomSource
import net.minecraft.world.InteractionResult
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
@@ -32,9 +31,13 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.CollisionGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.*
import net.minecraft.world.level.block.BaseEntityBlock
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.HorizontalDirectionalBlock
import net.minecraft.world.level.block.Mirror
import net.minecraft.world.level.block.RenderShape
import net.minecraft.world.level.block.Rotation
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
@@ -45,11 +48,9 @@ import net.minecraft.world.level.block.state.properties.IntegerProperty
import net.minecraft.world.level.block.state.properties.Property
import net.minecraft.world.level.pathfinder.PathComputationType
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraft.world.phys.shapes.VoxelShape
import java.util.Optional
@Suppress("DEPRECATED", "OVERRIDE_DEPRECATION")
class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
@@ -78,14 +79,6 @@ class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
const val MAX_CHARGE_LEVEL = 5
val CHARGE_LEVEL: IntegerProperty = IntegerProperty.create("charge", 0, MAX_CHARGE_LEVEL + 1)
val NATURAL: BooleanProperty = BooleanProperty.create("natural")
fun canSetSpawn(level: Level): Boolean {
return level.gameRules.getBoolean(CobblemonGameRules.HEALER_SET_SPAWN)
}
fun findStandUpPosition(entityType: EntityType<*>, level: CollisionGetter, pos: BlockPos): Optional<Vec3> {
return RespawnAnchorBlock.findStandUpPosition(entityType, level, pos) // Exists if we ever want to make something more custom, but anchor block logic should suffice
}
}
init {
@@ -165,12 +158,7 @@ class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
}
val party = serverPlayerEntity.party()
val pc = serverPlayerEntity.pc()
val healPC = player.level().gameRules.getBoolean(CobblemonGameRules.HEALERS_HEAL_PC)
// Do spawnpoint stuff
if (canSetSpawn(world)) {
player.setRespawnPosition(world.dimension(), blockPos, player.yRot, false, true)
}
val healPC = player.level().gameRules.getBoolean(CobblemonGameRules.HEALERS_HEAL_PC);
if (party.none() && (!healPC || pc.none())) {
player.sendSystemMessage(lang("healingmachine.nopokemon").red(), true)
@@ -195,7 +183,6 @@ class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
player.sendSystemMessage(lang("healingmachine.notenoughcharge", "${((neededCharge/party.count())*100f).toInt()}%").red(), true)
}
party.forEach { it.tryRecallWithAnimation() }
return InteractionResult.CONSUME
}
@@ -160,8 +160,8 @@ class TypeGemClusterBlock(
&& state.getValue(STAGE) == 3) return false
val supportPos = pos.relative(state.getValue(FACING).opposite)
val supportState = level.getBlockState(supportPos)
return supportState.`is`(CobblemonBlockTags.TYPE_GEM_BLOCKS) || supportState.block == CobblemonBlocks.TYPE_GEM_CORE // Cannot grow if not on any gem blocks
val supportBlock = level.getBlockState(supportPos).block
return CobblemonBlocks.typeGemBlocks().containsValue(supportBlock) || (supportBlock == CobblemonBlocks.TYPE_GEM_CORE) // Cannot grow if not on any gem blocks
}
@@ -22,6 +22,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.RandomSource
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.LevelAccessor
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
@@ -51,20 +52,10 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
ResourceLocation.parse("cobblemon:dragon_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_DRAGON,
ResourceLocation.parse("cobblemon:dark_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_DARK,
ResourceLocation.parse("cobblemon:steel_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_STEEL,
ResourceLocation.parse("cobblemon:fairy_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_FAIRY,
ResourceLocation.parse("minecraft:amethyst_block") to Blocks.SMALL_AMETHYST_BUD
ResourceLocation.parse("cobblemon:fairy_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_FAIRY
)
}
val AMETHYST_STAGES = listOf(
Blocks.SMALL_AMETHYST_BUD,
Blocks.MEDIUM_AMETHYST_BUD,
Blocks.LARGE_AMETHYST_BUD,
Blocks.AMETHYST_CLUSTER
)
private fun isAmethystStage(block: Block) = block in AMETHYST_STAGES
fun getConnectedGemBlocks(level: BlockGetter, pos: BlockPos): List<Pair<BlockState, BlockPos>> {
val connectedGems = mutableListOf<Pair<BlockState, BlockPos>>()
val visited = mutableSetOf<BlockPos>()
@@ -95,16 +86,12 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
Direction.entries.forEach {
if (random.nextFloat() < Cobblemon.config.typeGemGrowthChance) {
val faceState = level.getBlockState(pos.relative(it))
var newState = BLOCK_TO_CLUSTER[BuiltInRegistries.BLOCK.getKey(state.block)]?.defaultBlockState()
val randomGrowthType = decideClusterGrowthType(level, pos)
val newState = BLOCK_TO_CLUSTER[BuiltInRegistries.BLOCK.getKey(state.block)]?.defaultBlockState()
?.setValue(DirectionalBlock.FACING, it)
?.setValue(GROWTH_TYPE, randomGrowthType)
?: return
if (newState.hasProperty(GROWTH_TYPE)) {
newState = newState.setValue(GROWTH_TYPE, decideClusterGrowthType(level, pos))
} else if (getConnectedGemBlocks(level, pos).size > Cobblemon.config.typeGemMaxConnected) {
return@forEach
}
if (faceState.`is`(Blocks.AIR)) {
level.setBlock(pos.relative(it), newState, 3)
}
@@ -146,7 +133,7 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
if (!visited.add(clusterPos)) continue
val clusterState = level.getBlockState(clusterPos)
if (clusterState.block == expectedCluster && clusterState.hasProperty(GROWTH_TYPE)) {
if (clusterState.block == expectedCluster) {
clusters += clusterState to clusterPos
}
}
@@ -154,6 +141,19 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
return clusters
}
override fun onRemove(
state: BlockState,
level: Level,
pos: BlockPos,
newState: BlockState,
movedByPiston: Boolean
) {
getConnectedClusters(level, pos).forEach { // Stop growth of connected gems when core is removed
level.setBlockAndUpdate(it.second, it.first.setValue(GROWTH_TYPE, GrowthType.DECORATION))
}
super.onRemove(state, level, pos, newState, movedByPiston)
}
override fun randomTick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
// should we tick at all?
if (random.nextFloat() >= Cobblemon.config.typeGemTickChance) {
@@ -192,41 +192,13 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
Direction.entries.forEach { direction ->
val relativePos = pos.relative(direction)
val relativeState = level.getBlockState(relativePos)
val matchesFace = relativeState.hasProperty(DirectionalBlock.FACING)
&& relativeState.getValue(DirectionalBlock.FACING) == direction
if (!(forceGrow || (matchesFace && random.nextFloat() < Cobblemon.config.typeGemGrowthChance))) {
return@forEach
val clusterBlock = relativeState.block as? TypeGemClusterBlock ?: return@forEach
if ((relativeState.getValue(DirectionalBlock.FACING) == direction &&
random.nextFloat() < Cobblemon.config.typeGemGrowthChance) || forceGrow
) {
clusterBlock.advanceGrowth(relativeState, level, relativePos, random)
}
val block = relativeState.block
if (block is TypeGemClusterBlock) {
block.advanceGrowth(relativeState, level, relativePos, random)
} else if (isAmethystStage(block)) {
advanceAmethyst(relativeState, level, relativePos)
}
}
}
private fun advanceAmethyst(state: BlockState, level: LevelAccessor, pos: BlockPos) {
val facing = state.getValue(DirectionalBlock.FACING)
val supportState = level.getBlockState(pos.relative(facing.opposite))
if (!supportState.`is`(CobblemonBlockTags.TYPE_GEM_BLOCKS) && supportState.block != CobblemonBlocks.TYPE_GEM_CORE) {
return
}
if (state.block != Blocks.AMETHYST_CLUSTER) {
val nextStage = AMETHYST_STAGES[AMETHYST_STAGES.indexOf(state.block) + 1]
level.setBlock(pos, nextStage.defaultBlockState().setValue(DirectionalBlock.FACING, facing), 3)
return
}
// Fully grown clusters mature into amethyst blocks unless boxed in, mirroring stunted type gems
val boxedIn = Direction.entries.any { direction ->
direction != facing.opposite
&& level.getBlockState(pos.relative(direction)).`is`(CobblemonBlockTags.TYPE_GEM_BLOCKS)
}
if (!boxedIn) {
level.setBlock(pos, Blocks.AMETHYST_BLOCK.defaultBlockState(), 3)
}
}
@@ -9,13 +9,10 @@
package com.cobblemon.mod.common.client
import com.cobblemon.mod.common.BakingOverride
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.item.bag.CobblemonBagItem
import com.cobblemon.mod.common.util.cobblemonModel
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.resources.model.ModelResourceLocation
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
/**
* The purpose of this class is to hold models that we want baked, but aren't associated with
@@ -106,33 +103,9 @@ object CobblemonBakingOverrides {
cobblemonModel("surprise_mulch", "none")
)
// Bag
val bagModels = mutableMapOf<CobblemonBagItem, BakingOverride>()
val TRAINER_PACK = registerBagOverride(
CobblemonItems.TRAINER_PACK,
cobblemonResource("item/bag/trainer_pack"),
cobblemonModel("trainer_pack", "none")
)
val TRAINER_BAG = registerBagOverride(
CobblemonItems.TRAINER_BAG,
cobblemonResource("item/bag/trainer_bag"),
cobblemonModel("trainer_bag", "none")
)
/*val BAG_PENNY = registerBagOverride(
CobblemonItems.TRAINER_PACK,
cobblemonResource("item/bag/bag_penny"),
cobblemonModel("bag_penny", "penny")
)*/
fun registerOverride(modelLocation: ResourceLocation, modelIdentifier: ModelResourceLocation): BakingOverride {
val result = BakingOverride(modelLocation, modelIdentifier)
models.add(result)
return result
}
fun registerBagOverride(associatedItem: CobblemonBagItem, modelLocation: ResourceLocation, modelIdentifier: ModelResourceLocation): BakingOverride {
val result = registerOverride(modelLocation, modelIdentifier)
bagModels[associatedItem] = result
return result
}
}
@@ -27,7 +27,6 @@ import com.cobblemon.mod.common.client.battle.ClientBattle
import com.cobblemon.mod.common.client.gui.PartyOverlay
import com.cobblemon.mod.common.client.gui.PartyOverlayDataControl
import com.cobblemon.mod.common.client.gui.RideControlsOverlay
import com.cobblemon.mod.common.client.gui.bag.CobblemonBagScreen
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
import com.cobblemon.mod.common.client.gui.party.PartyTutorialToasts
@@ -47,7 +46,6 @@ import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
import com.cobblemon.mod.common.client.render.layer.PlayerRecallBallRenderer
import com.cobblemon.mod.common.client.render.layer.CobblemonBagRenderer
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
@@ -393,7 +391,7 @@ object CobblemonClient {
CobblemonBlocks.X_SP_ATK,
CobblemonBlocks.X_SP_DEF,
CobblemonBlocks.X_SPEED,
CobblemonBlocks.TM_MACHINE,
CobblemonBlocks.TM_MACHINE,
CobblemonBlocks.GALARICA_CUFF,
CobblemonBlocks.GALARICA_WREATH,
@@ -421,7 +419,7 @@ object CobblemonClient {
CobblemonBlocks.MOOMOO_MILK,
CobblemonBlocks.MEDICINAL_BREW,
CobblemonBlocks.TERRAIN_EXTENDER,
CobblemonBlocks.RED_MINT_LEAF_LITTER,
CobblemonBlocks.POTTED_RED_MINT,
CobblemonBlocks.BLUE_MINT_LEAF_LITTER,
@@ -541,17 +539,14 @@ object CobblemonClient {
skinMap?.get(PlayerSkin.Model.WIDE) as LivingEntityRenderer<Player, PlayerModel<Player>>
renderer?.addLayer(PokemonOnShoulderRenderer(renderer))
renderer?.addLayer(PlayerRecallBallRenderer(renderer))
renderer?.addLayer(CobblemonBagRenderer(renderer))
renderer = skinMap[PlayerSkin.Model.SLIM] as LivingEntityRenderer<Player, PlayerModel<Player>>?
renderer?.addLayer(PokemonOnShoulderRenderer(renderer))
renderer?.addLayer(PlayerRecallBallRenderer(renderer))
renderer?.addLayer(CobblemonBagRenderer(renderer))
}
private fun registerMenuScreens() {
MenuScreens.register(CobblemonMenuType.COOKING_POT, ::CookingPotScreen)
MenuScreens.register(CobblemonMenuType.TM_MACHINE, ::TMMachineScreen)
MenuScreens.register(CobblemonMenuType.COBBLEMON_BAG, ::CobblemonBagScreen)
}
private fun registerBlockEntityRenderers() {
@@ -1,88 +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.bag
import com.cobblemon.mod.common.api.bag.BagCategories
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
import net.minecraft.client.sounds.SoundManager
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
class BagCategoryButton(
x: Int,
y: Int,
val parent: CobblemonBagScreen,
val category: Int,
val action: OnPress
): Button(x, y, WIDTH, HEIGHT, Component.empty(), action, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 32
private const val HEIGHT = 31
private val CATEGORY_SLOT = cobblemonResource("textures/gui/bag/bag_tab.png")
private val VOLUME_BAR = cobblemonResource("textures/gui/bag/bag_tab_volume_bar.png")
}
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
val orderedCategories = BagCategories.getOrderedCategoriesList()
blitk(
matrixStack = context.pose(),
texture = CATEGORY_SLOT,
x = x, y = y,
width = WIDTH, height = HEIGHT,
textureHeight = 64,
vOffset = if (parent.menu.currentlySelectedCategory == category) 32 else 0
)
blitk(
matrixStack = context.pose(),
texture = if (category == -1) ResourceLocation("minecraft", "textures/item/bundle.png") else orderedCategories[category].icon,
x = x + 8, y = y + 9,
width = 16, height = 16
)
//The Bar
if (category != -1) {
blitk(
matrixStack = context.pose(),
texture = VOLUME_BAR,
x = x + 8, y = y + 25,
width = 16, height = 3
)
val itemRatio = (parent.menu.categoryItemCounts[category].toFloat() / orderedCategories[category].maxCount).coerceIn(0F, 1F)
val barWidth = itemRatio * 14
val (red, green) = getDepletableRedGreen(1 - itemRatio)
blitk(
matrixStack = context.pose(),
texture = CobblemonResources.WHITE,
x = x + 9, y = y + 26,
width = barWidth, height = 1,
red = red * 0.8F, green = green * 0.8F, blue = 0.27F
)
}
if (isHovered) {
context.renderTooltip(Minecraft.getInstance().font, if (category == -1) lang("bag_categories.all_items") else orderedCategories[category].getName(), mouseX, mouseY)
}
}
override fun playDownSound(handler: SoundManager) {}
}
@@ -1,50 +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.bag
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.components.Button
import net.minecraft.client.sounds.SoundManager
import net.minecraft.network.chat.Component
class BagCategoryPageButton(
x: Int,
y: Int,
val parent: CobblemonBagScreen,
val leftButton: Boolean,
val action: OnPress
): Button(x, y, WIDTH, HEIGHT, Component.empty(), action, DEFAULT_NARRATION), CobblemonRenderable {
companion object {
private const val WIDTH = 12
private const val HEIGHT = 10
private val LEFT_BUTTON = cobblemonResource("textures/gui/bag/button_left.png")
private val RIGHT_BUTTON = cobblemonResource("textures/gui/bag/button_right.png")
}
var enabled = true
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
blitk(
matrixStack = context.pose(),
texture = if (leftButton) LEFT_BUTTON else RIGHT_BUTTON,
x = x / 0.5F, y = y / 0.5F,
width = WIDTH * 2, height = HEIGHT * 2,
textureHeight = 40,
vOffset = if (enabled) 20 else 0,
scale = 0.5f
)
}
override fun playDownSound(handler: SoundManager) {}
}
@@ -1,416 +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.bag
import com.cobblemon.mod.common.CobblemonNetwork.sendToServer
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.bag.BagCategories
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.drawProfilePokemon
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
import com.cobblemon.mod.common.client.render.getDepletableRedGreen
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
import com.cobblemon.mod.common.item.bag.CobblemonBagMenu
import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.net.messages.client.bag.UpdateBagMenuDataPacket
import com.cobblemon.mod.common.net.messages.client.bag.UseItemOnPokemonFromBagPacket
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
import juuxel.adorn.util.Colors
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.network.chat.Component
import net.minecraft.sounds.SoundEvent
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.ClickType
import net.minecraft.world.inventory.Slot
import org.joml.Quaternionf
import org.joml.Vector3f
import kotlin.math.min
import kotlin.math.roundToInt
@Environment(EnvType.CLIENT)
class CobblemonBagScreen(
menu: CobblemonBagMenu,
playerInventory: Inventory,
title: Component
): AbstractContainerScreen<CobblemonBagMenu>(
menu,
playerInventory,
Component.translatable("cobblemon.container.bag")
) {
companion object {
private const val BACKGROUND_HEIGHT = 197
private const val BACKGROUND_WIDTH = 184
private val BACKGROUND = cobblemonResource("textures/gui/bag/bag_base.png")
private val SCROLL_TRACK = cobblemonResource("textures/gui/bag/scrollbar_track.png")
private val SCROLL_SLIDE = cobblemonResource("textures/gui/bag/scrollbar_slide.png")
private val PARTY_SLOT_BASE = cobblemonResource("textures/gui/bag/party_slot_base.png")
private val PARTY_SLOT_COLLAPSED = cobblemonResource("textures/gui/bag/party_slot_collapsed.png")
private val PARTY_SLOT = cobblemonResource("textures/gui/bag/party_slot.png")
private val PARTY_SLOT_FAINTED = cobblemonResource("textures/gui/bag/party_slot_fainted.png")
private val GENDER_ICON_MALE = cobblemonResource("textures/gui/party/party_gender_male.png")
private val GENDER_ICON_FEMALE = cobblemonResource("textures/gui/party/party_gender_female.png")
}
val categoriesWidgets = mutableListOf<BagCategoryButton>()
lateinit var allItemsCategoryWidget: BagCategoryButton
lateinit var leftCategoryPageButton: BagCategoryPageButton
lateinit var rightCategoryPageButton: BagCategoryPageButton
var currentCategoryPage = 0
var lastCategory = menu.currentlySelectedCategory
var lastScroll = menu.scroll
var scrolling = false
init {
this.imageWidth = BACKGROUND_WIDTH + 69
this.imageHeight = BACKGROUND_HEIGHT + 27
}
override fun init() {
super.init()
this.leftPos -= 34
for (i in 0..3) {
if (i < BagCategories.getOrderedCategoriesList().size) {
categoriesWidgets.add(
BagCategoryButton(leftPos + 76 + i * 33, topPos, this, i) {
if (menu.currentlySelectedCategory != i) {
menu.changeCategory(i)
playSound(CobblemonSounds.ITEM_BAG_CLICK)
}
}.also { addRenderableWidget(it) }
)
} else break
}
allItemsCategoryWidget = BagCategoryButton(leftPos + 214, topPos, this, -1) {
if (menu.currentlySelectedCategory != -1) {
menu.changeCategory(-1)
playSound(CobblemonSounds.ITEM_BAG_CLICK)
}
}.also { addRenderableWidget(it) }
leftCategoryPageButton = BagCategoryPageButton(leftPos + 218, topPos + 32, this, true) {
if (leftCategoryPageButton.enabled) {
cycleCategoryPage(false)
playSound(CobblemonSounds.ITEM_BAG_CLICK)
}
}.also { addRenderableWidget(it) }
rightCategoryPageButton = BagCategoryPageButton(leftPos + 229, topPos + 32, this, false) {
if (rightCategoryPageButton.enabled) {
cycleCategoryPage(true)
playSound(CobblemonSounds.ITEM_BAG_CLICK)
}
}.also { addRenderableWidget(it) }
playSound(CobblemonSounds.ITEM_BAG_OPEN)
}
override fun renderBg(context: GuiGraphics, partialTick: Float, mouseX: Int, mouseY: Int) {}
override fun renderBackground(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {}
override fun renderLabels(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int) {}
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) {
renderTransparentBackground(context)
val matrices = context.pose()
// Background
blitk(
matrixStack = matrices,
texture = BACKGROUND,
x = leftPos + 69, y = topPos + 27,
width = BACKGROUND_WIDTH, height = BACKGROUND_HEIGHT
)
//Scroll
val scrollYOffset = if (menu.maxScroll == 0) {
if (menu.scroll == 0) 0 else 53
} else ((min(menu.scroll, menu.maxScroll).toFloat() / menu.maxScroll) * 53).toInt()
val trackHeight = 71 - scrollYOffset - 13
if (trackHeight > 0) {
blitk(
matrixStack = matrices,
texture = SCROLL_TRACK,
x = leftPos + 230, y = topPos + 49 + (71 - trackHeight),
width = 9, height = trackHeight,
textureHeight = 71,
vOffset = 71 - trackHeight
)
}
blitk(
matrixStack = matrices,
texture = SCROLL_SLIDE,
x = leftPos + 230, y = topPos + 49 + scrollYOffset,
width = 9, height = 17
)
// Pokemon
val party = CobblemonClient.storage.party
for (i in 0..5) {
val pokemon = party.get(i)
val slotYPosition = topPos + i * 33 + 27
if (pokemon != null) {
blitk(
matrixStack = matrices,
texture = PARTY_SLOT_BASE,
x = leftPos, y = slotYPosition,
width = 67, height = 31
)
val slotWidth = 32
val slotLeft = leftPos + 11
blitk(
matrixStack = matrices,
texture = if (pokemon.isFainted()) PARTY_SLOT_FAINTED else PARTY_SLOT,
x = slotLeft, y = slotYPosition,
width = slotWidth, height = 26,
textureHeight = 52,
vOffset = if (!menu.carried.isEmpty && menu.carried.item is BagItem && partySlotHovered(i, mouseX, mouseY)) 26 else 0
)
val expForThisLevel = pokemon.experience - pokemon.experienceGroup.getExperience(pokemon.level)
val expToNextLevel = pokemon.experienceGroup.getExperience(pokemon.level + 1) - pokemon.experienceGroup.getExperience(pokemon.level)
val expRatio = expForThisLevel.toFloat() / expToNextLevel
val expBarHeight = expRatio * 20
if (expBarHeight > 0) {
blitk(
matrixStack = matrices,
texture = CobblemonResources.WHITE,
x = leftPos + 6, y = slotYPosition + 24 - expBarHeight,
width = 1, height = expBarHeight,
red = 0.2, green = 0.65, blue = 0.84
)
}
val hpRatio = pokemon.currentHealth.toFloat() / pokemon.maxHealth
val hpBarHeight = hpRatio * 20
val (red, green) = getDepletableRedGreen(hpRatio)
if (hpBarHeight > 0) {
blitk(
matrixStack = matrices,
texture = CobblemonResources.WHITE,
x = leftPos + 8, y = slotYPosition + 24 - hpBarHeight,
width = 2, height = hpBarHeight,
red = red * 0.8F, green = green * 0.8F, blue = 0.27F
)
}
// Ball Icon
val ballIcon = cobblemonResource("textures/gui/ball/" + pokemon.caughtBall.name.path + ".png")
blitk(
matrixStack = matrices,
texture = ballIcon,
x = (leftPos + 3.5F) / 0.5F, y = (slotYPosition + 23) / 0.5F,
width = 18, height = 22,
textureHeight = 44,
scale = 0.5F
)
//Gender
if (pokemon.gender != Gender.GENDERLESS) {
blitk(
matrixStack = matrices,
texture = if (pokemon.gender == Gender.MALE) GENDER_ICON_MALE else GENDER_ICON_FEMALE,
x = (leftPos + 62) / 0.5F, y = (slotYPosition + 26) / 0.5F,
width = 5, height = 7,
scale = 0.5F
)
}
//Status
val status = pokemon.status?.status
if (!pokemon.isFainted() && status != null) {
blitk(
matrixStack = matrices,
texture = cobblemonResource("textures/gui/bag/status_${status.showdownName}.png"),
x = leftPos + 1, y = slotYPosition + 9,
width = 4, height = 14
)
}
matrices.pushPose()
matrices.translate(slotLeft + ((slotWidth - 8) / 2.0), slotYPosition.toDouble() - 6, 0.0)
matrices.scale(3.5F, 3.5F, 1F)
val state = FloatingState()
state.currentAspects = pokemon.aspects
drawProfilePokemon(
species = pokemon.species.resourceIdentifier,
matrixStack = matrices,
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
state = state,
scale = 4.5F,
partialTicks = 0F
)
matrices.popPose()
matrices.pushPose()
matrices.translate(0.0, 0.0, 100.0)
// Level and Name and Gender
drawScaledText(
context = context,
text = pokemon.getDisplayName(),
x = leftPos + 14, y = slotYPosition + 26,
scale = 0.5F
)
drawScaledTextJustifiedRight(
context = context,
text = lang("ui.lv"),
x = leftPos + 40, y = slotYPosition + 14,
shadow = true,
scale = 0.5F
)
drawScaledTextJustifiedRight(
context = context,
text = pokemon.level.toString().text(),
x = leftPos + 40, y = slotYPosition + 19,
shadow = true,
scale = 0.5F
)
matrices.popPose()
} else {
blitk(
matrixStack = matrices,
texture = PARTY_SLOT_COLLAPSED,
x = leftPos + 64, y = slotYPosition,
width = 5, height = 31
)
}
}
//Titles
context.drawString(font, title, leftPos + 80, topPos + 33, Colors.WHITE, false)
context.drawString(font, playerInventoryTitle, leftPos + 80, topPos + 129, 4210752, false)
super.render(context, mouseX, mouseY, partialTick)
renderTooltip(context, mouseX, mouseY)
}
fun partySlotHovered(index: Int, mouseX: Int, mouseY: Int): Boolean {
val left = leftPos + 11
val top = topPos + index * 33 + 27
return mouseX in left..(left + 32) && mouseY in top..(top + 26)
}
fun cycleCategoryPage(next: Boolean) {
val orderedCategories = BagCategories.getOrderedCategoriesList()
currentCategoryPage = (currentCategoryPage + if (next) 1 else -1).coerceIn(0, (orderedCategories.size - 1) / 4)
categoriesWidgets.forEach {
removeWidget(it)
}
categoriesWidgets.clear()
for (i in 0..3) {
val adjustedIndex = i + 4 * currentCategoryPage
if (adjustedIndex < orderedCategories.size) {
categoriesWidgets.add(
BagCategoryButton(leftPos + 76 + i * 33, topPos, this, adjustedIndex) {
playSound(CobblemonSounds.ITEM_BAG_CLICK)
menu.changeCategory(adjustedIndex)
}.also { addRenderableWidget(it) }
)
} else break
}
leftCategoryPageButton.enabled = currentCategoryPage > 0
rightCategoryPageButton.enabled = currentCategoryPage < (orderedCategories.size - 1) / 4
}
fun updateScrollValue(mouseY: Double) {
val adjustedMouseY = mouseY - topPos - 49.0
if (adjustedMouseY < 0) {
menu.scroll = 0
} else if (adjustedMouseY > 71) {
menu.scroll = menu.maxScroll
} else {
menu.scroll = ((adjustedMouseY / 71.0) * (menu.maxScroll)).roundToInt()
}
menu.setupSlotsBasedOnContent()
}
override fun slotClicked(slot: Slot?, slotId: Int, mouseButton: Int, type: ClickType) {
if (slotId in CobblemonBagMenu.BAG_SLOTS && (lastCategory != menu.currentlySelectedCategory || lastScroll != menu.scroll)) {
lastCategory = menu.currentlySelectedCategory
lastScroll = menu.scroll
sendToServer(UpdateBagMenuDataPacket(menu.currentlySelectedCategory, menu.scroll)) // Synchronize this data
}
super.slotClicked(slot, slotId, mouseButton, type)
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
if (scrollY < 0 && menu.scroll < menu.maxScroll) {
menu.scroll += 1
} else if (scrollY > 0 && menu.scroll > 0) {
menu.scroll -= 1
}
menu.setupSlotsBasedOnContent()
return true
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (mouseX in (leftPos + 229.0)..(leftPos + 240.0) && mouseY in (topPos + 49.0)..(topPos + 120.0)) {
scrolling = true
updateScrollValue(mouseY)
return true
}
val party = CobblemonClient.storage.party
if (!menu.carried.isEmpty && menu.carried.item is BagItem) {
for (i in 0..5) {
if (party.get(i) != null && partySlotHovered(i, mouseX.toInt(), mouseY.toInt())) {
playSound(CobblemonSounds.GUI_CLICK)
sendToServer(UseItemOnPokemonFromBagPacket(i))
return true
}
}
}
return super.mouseClicked(mouseX, mouseY, button)
}
override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
scrolling = false
return super.mouseReleased(mouseX, mouseY, button)
}
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, dragX: Double, dragY: Double): Boolean {
if (scrolling) {
updateScrollValue(mouseY)
return true
}
return super.mouseDragged(mouseX, mouseY, button, dragX, dragY)
}
fun playSound(soundEvent: SoundEvent) {
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1.0F))
}
override fun onClose() {
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.ITEM_BAG_CLOSE, 1.0F))
super.onClose()
}
}
@@ -748,6 +748,8 @@ class PokedexGUI private constructor(
}
TAB_DROPS -> {
(tabInfoElement as DropsScrollingWidget).dropTable = form.drops
(tabInfoElement as DropsScrollingWidget).form = form
(tabInfoElement as DropsScrollingWidget).aspects = aspects.toSet()
(tabInfoElement as DropsScrollingWidget).setEntries()
}
TAB_MOVES -> {
@@ -10,6 +10,9 @@ package com.cobblemon.mod.common.client.gui.pokedex.widgets
import com.cobblemon.mod.common.api.drop.DropTable
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.drop.LootTableDropEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.ScrollingWidget
@@ -17,17 +20,27 @@ import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.itemRegistry
import com.cobblemon.mod.common.util.lang
import java.text.DecimalFormat
import com.cobblemon.mod.common.util.server
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import net.minecraft.ChatFormatting
import net.minecraft.Util
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.core.registries.Registries
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.util.FastColor
import net.minecraft.util.Mth
import net.minecraft.world.item.ItemStack
import java.text.DecimalFormat
class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrollingWidget.DropWidgetEntry>(
width = PokedexGUIConstants.HALF_OVERLAY_WIDTH - 2,
@@ -38,6 +51,8 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
) {
var dropTable: DropTable = DropTable()
var aspects: Set<String> = emptySet()
var form: FormData = FormData()
companion object {
val df = DecimalFormat("#.##")
@@ -50,9 +65,157 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
override fun getX() = pX
override fun getY() = pY
private fun getFormAspects(): Set<String> {
val formAspects = form.species.forms
.flatMapTo(mutableSetOf()) { it.aspects }
.apply { addAll(form.species.standardForm.aspects) }
val selectedFormAspectPrefixes = form.aspects
.mapNotNull { it.substringBeforeLast('-', "").takeIf(String::isNotEmpty) }
.toSet()
return formAspects + aspects.filter { aspect ->
val prefix = aspect.substringBeforeLast('-', "")
prefix.isNotEmpty() && prefix in selectedFormAspectPrefixes
}
}
private fun checkPokemonConditions(condition: JsonObject): Boolean {
val conditionType = condition["condition"].asString
if (conditionType == "cobblemon:requirement") {
val requirementJson = condition["requirement"].asJsonObject
val selectedAspects = (aspects - getFormAspects()) + form.aspects
val requirement = PokemonSpecies.gson.fromJson(requirementJson, Requirement::class.java)
val tempPokemon = Pokemon().apply { species = form.species }
tempPokemon.form = form
tempPokemon.forcedAspects = selectedAspects
tempPokemon.shiny = "shiny" in selectedAspects
tempPokemon.updateAspects()
return requirement.check(tempPokemon)
}
if (conditionType == "minecraft:all_of") {
val terms = condition["terms"]?.asJsonArray ?: return true
return terms.all {
checkPokemonConditions(it.asJsonObject)
}
}
if (conditionType == "minecraft:any_of") {
val terms = condition["terms"]?.asJsonArray ?: return true
return terms.any {
checkPokemonConditions(it.asJsonObject)
}
}
if (conditionType == "minecraft:inverted") {
val term = condition["term"]?.asJsonObject ?: return true
return !checkPokemonConditions(term)
}
return true
}
fun setEntries() {
dropTable.entries.forEach {
if (it is ItemDropEntry) addEntry(DropWidgetEntry(it))
clearEntries()
dropTable.entries.forEach { it ->
if (it is ItemDropEntry) {
addEntry(DropWidgetEntry(it, mutableSetOf(it.item)))
} else if (it is LootTableDropEntry) { // LootTable doesn't expose pools, so we gotta do all this bullshit
val server = server() ?: return
val lootTableResource = ResourceLocation.fromNamespaceAndPath(
it.id.namespace,
"loot_table/${it.id.path}.json"
)
val resource = server.resourceManager
.getResource(lootTableResource)
.orElse(null)
?: return@forEach
val json = resource.openAsReader().use { reader ->
JsonParser.parseReader(reader).asJsonObject
}
json.getAsJsonArray("pools")?.forEach { poolElement ->
val pool = poolElement.asJsonObject
val entries = pool.getAsJsonArray("entries") ?: return@forEach
val validEntries = entries
.map { entryElement -> entryElement.asJsonObject }
.filter { entry ->
val conditions = entry["conditions"]?.asJsonArray ?: JsonArray()
conditions.all { condition ->
val conditionJson = condition.asJsonObject
checkPokemonConditions(conditionJson)
}
}
val totalWeight = validEntries.sumOf { entry ->
entry["weight"]?.asInt ?: 1
}
for (entry in validEntries) {
val dropEntry = ItemDropEntry()
val conditions = entry["conditions"]?.asJsonArray ?: JsonArray()
val functions = entry["functions"]?.asJsonArray ?: JsonArray()
val items = mutableSetOf<ResourceLocation>()
var tag: ResourceLocation? = null
if (validEntries.size > 1 && totalWeight > 0) {
val weight = entry["weight"]?.asInt ?: 1
dropEntry.percentage = weight.toFloat() / totalWeight.toFloat() * 100F
}
conditions.forEach { condition ->
val conditionJson = condition.asJsonObject
val conditionType = conditionJson["condition"].asString
if (conditionType == "minecraft:random_chance") {
val chance = conditionJson["chance"].asFloat * 100F
if (validEntries.size > 1) {
dropEntry.percentage *= chance / 100F
} else {
dropEntry.percentage = chance
}
}
}
functions.forEach { function ->
val functionObj = function.asJsonObject
if (functionObj["function"].asString == "set_count") {
val count = functionObj["count"].asJsonObject
val min = count["min"].asInt
val max = count["max"].asInt
dropEntry.quantityRange = IntRange(min, max)
}
}
if (entry["type"].asString == "minecraft:tag") {
val itemRegistry = Minecraft.getInstance()
.level!!
.registryAccess()
.lookupOrThrow(Registries.ITEM)
val tagKey = TagKey.create(Registries.ITEM, ResourceLocation.parse(entry["name"].asString))
tag = tagKey.location
val tagItems = itemRegistry.getOrThrow(tagKey)
.stream()
.map { holder ->
holder.unwrapKey().map {
it.location()
}.orElse(null)
}.toList().filterNotNull()
items.addAll(tagItems)
} else if (entry["type"].asString == "minecraft:item") {
items.add(ResourceLocation.parse(entry["name"].asString))
}
addEntry(DropWidgetEntry(dropEntry, items, tag))
}
}
}
}
}
@@ -90,7 +253,7 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
shadow = true
)
if (dropTable.entries.size == 0) {
if (dropTable.entries.isEmpty()) {
drawScaledText(
context = context,
text = lang("ui.pokedex.info.drops_empty"),
@@ -128,7 +291,7 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
return children()[index] as DropWidgetEntry
}
class DropWidgetEntry(val entry: ItemDropEntry): Slot<DropWidgetEntry>() {
class DropWidgetEntry(val entry: ItemDropEntry, val items: MutableSet<ResourceLocation>, val tag: ResourceLocation? = null): Slot<DropWidgetEntry>() {
override fun render(
context: GuiGraphics,
index: Int,
@@ -141,9 +304,14 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
hovered: Boolean,
tickDelta: Float
) {
if (items.isEmpty()) return
context.pose().pushPose()
context.pose().translate(0f, 0f, 100f)
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(entry.item)?.defaultInstance ?: ItemStack.EMPTY
val index = ((Util.getMillis() / 1000L) % items.size).toInt()
val itemLocation = items.elementAt(index)
val itemStack = Minecraft.getInstance().player?.level()?.itemRegistry?.get(itemLocation)?.defaultInstance ?: ItemStack.EMPTY
renderScaledGuiItemIcon(
itemStack = itemStack,
x = x.toDouble(),
@@ -151,28 +319,32 @@ class DropsScrollingWidget(val pX: Int, val pY: Int): ScrollingWidget<DropsScrol
matrixStack = context.pose(),
scale = PokedexGUIConstants.SCALE.toDouble()
)
context.pose().pushPose()
val min = entry.quantityRange?.min() ?: entry.quantity
val max = entry.quantityRange?.max() ?: entry.quantity
if (min == max) {
entry.quantity = min
entry.quantityRange = null
}
// var itemName: String = Component.translatable(itemStack.hoverName).string
// itemName = if (itemName.length > 24) {
// itemName.substring(0, 24 - 3) + "..."
// } else {
// itemName
// }
val displayName = if (tag == null) {
itemStack.hoverName.copy().withStyle(ChatFormatting.BOLD)
} else {
Component.translatable("tag.item.${tag.namespace}.${tag.path.replace('/', '.')}").withStyle(ChatFormatting.BOLD)
}
val displayText: MutableComponent = if (entry.quantityRange != null) {
lang(
"ui.pokedex.info.drops_display",
itemStack.hoverName.copy().withStyle(ChatFormatting.BOLD),
displayName,
lang("ui.pokedex.info.drops_range", min, max)
)
} else {
lang(
"ui.pokedex.info.drops_display",
itemStack.hoverName.copy().withStyle(ChatFormatting.BOLD),
displayName,
lang("ui.pokedex.info.drops_amount", entry.quantity)
)
}
@@ -28,9 +28,9 @@ import org.joml.Vector3f
open class PartySlot(
x: Int, y: Int,
val pokemon: TradeStartedPacket.TradeablePokemon?,
private val pokemon: TradeStartedPacket.TradeablePokemon?,
private val parent: TradeGUI,
val isOpposing: Boolean = false,
private val isOpposing: Boolean = false,
onPress: OnPress
) : Button(x, y, SIZE, SIZE, Component.literal("PartySlot"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
val state = FloatingState()
@@ -42,8 +42,6 @@ open class PartySlot(
private val genderIconFemale = cobblemonResource("textures/gui/pc/gender_icon_female.png")
private val selectPointerResource = cobblemonResource("textures/gui/pc/pc_pointer.png")
private val untradeableResource = cobblemonResource("textures/gui/trade/trade_slot_icon_locked.png")
private val tradePartySlotSelectedResource = cobblemonResource("textures/gui/trade/trade_party_slot_selected.png")
private val tradePartySlotSelectedOpposingResource = cobblemonResource("textures/gui/trade/trade_party_slot_selected_opposing.png")
}
override fun playDownSound(soundManager: SoundManager) {
@@ -62,17 +60,6 @@ open class PartySlot(
)
}
if (hasSelected()) {
blitk(
matrixStack = matrices,
texture = if (isOpposing) tradePartySlotSelectedOpposingResource else tradePartySlotSelectedResource,
x = x - 2,
y = y - 2,
width = 29,
height = 29
)
}
if (pokemon != null) {
// context.enableScissor(x - 2, y + 2, x + SIZE + 4, y + SIZE + 4)
// Render Pokémon
@@ -131,16 +118,7 @@ open class PartySlot(
}
matrices.popPose()
val isViewed = if (isOpposing) {
parent.opposingOfferedPokemon?.uuid == pokemon.pokemonId
} else {
parent.offeredPokemon?.uuid == pokemon.pokemonId
}
if (isViewed && pokemon.tradeable) {
matrices.pushPose()
matrices.translate(0.0, 0.0, 200.0)
if (hasSelected()) {
blitk(
matrixStack = matrices,
texture = selectPointerResource,
@@ -150,7 +128,6 @@ open class PartySlot(
height = 8,
scale = TradeGUI.SCALE
)
matrices.popPose()
}
// Held Item
@@ -168,9 +145,8 @@ open class PartySlot(
}
open fun hasSelected(): Boolean {
if (pokemon == null) return false
val offeredPokemons = if (isOpposing) parent.trade.oppositeOffer.get() else parent.trade.myOffer.get()
return offeredPokemons.any { it.uuid == pokemon.pokemonId }
val offeredPokemon = if (isOpposing) parent.trade.oppositeOffer.get() else parent.trade.myOffer.get()
return pokemon?.pokemonId == offeredPokemon?.uuid && pokemon != null
}
fun isHovered(mouseX: Int, mouseY: Int) = pokemon?.tradeable != false && mouseX.toFloat() in (x.toFloat()..(x.toFloat() + SIZE)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + SIZE))
@@ -25,7 +25,6 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.common.reformatNature
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
import com.cobblemon.mod.common.client.trade.ClientTrade
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket.TradeablePokemon
import com.cobblemon.mod.common.net.messages.server.trade.*
import com.cobblemon.mod.common.pokemon.Gender
@@ -99,23 +98,15 @@ class TradeGUI(
private val tradeAnimationArrowsResource = cobblemonResource("textures/gui/trade/trade_animation_arrows.png")
}
private var offeredPokemonModels: MutableList<ModelWidget> = mutableListOf()
private var opposingOfferedPokemonModels: MutableList<ModelWidget> = mutableListOf()
private var offeredPokemonModel: ModelWidget? = null
private var opposingOfferedPokemonModel: ModelWidget? = null
private lateinit var offeredPokemonMarkings: MarkingsWidget
private lateinit var opposingOfferedPokemonMarkings: MarkingsWidget
var selectedPartyIndices = mutableListOf<Int>()
var offeredPokemons: MutableList<Pokemon> = mutableListOf()
var opposingPokemons: MutableList<Pokemon> = mutableListOf()
// For backwards compatibility where single is referenced in rendering text info
var offeredPokemon: Pokemon? = null
var opposingOfferedPokemon: Pokemon? = null
var myGridMode = true
var opposingGridMode = true
var ticksElapsed = 0
var protectiveTicks = 0
var selectPointerOffsetY = 0
@@ -134,67 +125,30 @@ class TradeGUI(
}
trade.completedEmitter.subscribe {
val (pokemonIds1, pokemonIds2) = it
val myTradedPokemons = pokemonIds1.mapNotNull { id -> party.find { it?.pokemonId == id } }
val theirTradedPokemons = pokemonIds2.mapNotNull { id -> traderParty.find { it?.pokemonId == id } }
if (myTradedPokemons.isEmpty() || theirTradedPokemons.isEmpty()) {
val (pokemonId1, pokemonId2) = it
val myTradedPokemon = party.find { it?.pokemonId == pokemonId1 }
val theirTradedPokemon = traderParty.find { it?.pokemonId == pokemonId2 }
if (myTradedPokemon == null || theirTradedPokemon == null) {
CobblemonNetwork.sendToServer(CancelTradePacket())
return@subscribe onClose()
}
myTradedPokemons.forEach { pk ->
val idx = party.indexOf(pk)
if (idx != -1) party[idx] = null
}
theirTradedPokemons.forEach { pk ->
val idx = traderParty.indexOf(pk)
if (idx != -1) traderParty[idx] = null
}
val newSelectedIndices = mutableListOf<Int>()
theirTradedPokemons.forEach { pk ->
val emptyIdx = party.indexOf(null)
if (emptyIdx != -1) {
party[emptyIdx] = pk
}
}
myTradedPokemons.forEach { pk ->
val emptyIdx = traderParty.indexOf(null)
if (emptyIdx != -1) traderParty[emptyIdx] = pk
}
val compactUI = { list: MutableList<TradeStartedPacket.TradeablePokemon?> ->
val nonNulls = list.filterNotNull()
list.clear()
list.addAll(nonNulls)
while (list.size < 6) list.add(null)
}
compactUI(party)
compactUI(traderParty)
theirTradedPokemons.forEach { pk ->
val idx = party.indexOf(pk)
if (idx != -1) newSelectedIndices.add(idx)
}
val tradedSlot = party.indexOf(myTradedPokemon)
val opposingTradedSlot = traderParty.indexOf(theirTradedPokemon)
party[tradedSlot] = theirTradedPokemon
traderParty[opposingTradedSlot] = myTradedPokemon
trade.oppositeAcceptedMyOffer.set(false)
selectedPartyIndices.clear()
selectedPartyIndices.addAll(newSelectedIndices)
val newOffers = selectedPartyIndices.mapNotNull { idx ->
party[idx]?.let { it.pokemonId to PartyPosition(idx) }
}
CobblemonNetwork.sendToServer(UpdateTradeOfferPacket(newOffers))
CobblemonNetwork.sendToServer(UpdateTradeOfferPacket(Pair(theirTradedPokemon.pokemonId, PartyPosition(tradedSlot))))
rebuildWidgets()
}
trade.oppositeOffer.subscribe { newOffer: List<Pokemon> ->
setOfferedPokemon(pokemonList = newOffer, isOpposing = true)
trade.oppositeOffer.subscribe { newOffer: Pokemon? ->
setOfferedPokemon(pokemon = newOffer, isOpposing = true)
}
trade.myOffer.subscribe { myOffer: List<Pokemon> ->
setOfferedPokemon(pokemonList = myOffer)
trade.myOffer.subscribe { myOffer: Pokemon? ->
setOfferedPokemon(pokemon = myOffer)
}
trade.oppositeAcceptedMyOffer.subscribe {
@@ -262,16 +216,9 @@ class TradeGUI(
pokemon = pokemon,
parent = this,
onPress = {
if (!trade.acceptedOppositeOffer && !tradeProcessing && pokemon != null) {
if (selectedPartyIndices.contains(partyIndex)) {
selectedPartyIndices.remove(partyIndex)
} else if (selectedPartyIndices.size < 6) {
selectedPartyIndices.add(partyIndex)
}
val newOffers = selectedPartyIndices.mapNotNull { idx ->
party[idx]?.let { it.pokemonId to PartyPosition(idx) }
}
CobblemonNetwork.sendToServer(UpdateTradeOfferPacket(newOffers))
if (!trade.acceptedOppositeOffer && !tradeProcessing) {
val pk = if (offeredPokemon?.uuid == pokemon?.pokemonId) null else pokemon
CobblemonNetwork.sendToServer(UpdateTradeOfferPacket(pk?.let { it.pokemonId to PartyPosition(partyIndex) }))
playSound(CobblemonSounds.GUI_CLICK)
}
}
@@ -303,8 +250,8 @@ class TradeGUI(
).also { widget -> addRenderableWidget(widget) }
}
setOfferedPokemon(pokemonList = offeredPokemons.toList(), isOpposing = false)
setOfferedPokemon(pokemonList = opposingPokemons.toList(), isOpposing = true)
setOfferedPokemon(pokemon = offeredPokemon, isOpposing = false)
setOfferedPokemon(pokemon = opposingOfferedPokemon, isOpposing = true)
offeredPokemonMarkings = MarkingsWidget(x + 74.5, y + 21, offeredPokemon, false)
opposingOfferedPokemonMarkings = MarkingsWidget(x + 177.5, y + 21, opposingOfferedPokemon, false)
@@ -337,7 +284,7 @@ class TradeGUI(
if (tradeAnimationProgress > REVERSE_ANIMATION_TICK)
(REVERSE_ANIMATION_TICK + TRADE_ANIMATION_FRAMES - tradeAnimationProgress)
else (tradeAnimationProgress - MODEL_SCALE_BUFFER_FRAMES)
) * TRADE_ANIMATION_HEIGHT
) * TRADE_ANIMATION_HEIGHT
blitk(
matrixStack = matrices,
texture = tradeAnimationResource,
@@ -366,56 +313,20 @@ class TradeGUI(
// Render Model Portraits
var scale = PORTRAIT_SCALE
var scaleOffsetY = PORTRAIT_MODEL_OFFSET_Y
var isShrinking = false
if (tradeProcessing) {
val scaleInterval = if (tradeAnimationProgress > REVERSE_ANIMATION_TICK) (MAX_TRADE_PROGRESS - tradeAnimationProgress) else tradeAnimationProgress
scale = (PORTRAIT_SCALE - (scaleInterval * PORTRAIT_SCALE_MULTIPLIER)).coerceIn(0F, PORTRAIT_SCALE)
scaleOffsetY = (45.0 - (45.0 / PORTRAIT_SCALE) * scale) + PORTRAIT_MODEL_OFFSET_Y
isShrinking = true
}
val shrinkPercentage = if (isShrinking) 1.0F - (scale / PORTRAIT_SCALE) else 0.0F
val myCenterXDest = x + 70 + (PORTRAIT_SIZE / 2.0)
val myCenterYDest = y + 30 + (PORTRAIT_SIZE / 2.0)
val opCenterXDest = x + 145 + (PORTRAIT_SIZE / 2.0)
val opCenterYDest = y + 30 + (PORTRAIT_SIZE / 2.0)
if (scale > 0F) {
context.enableScissor(backgroundX, backgroundY, backgroundX + BASE_BACKGROUND_WIDTH, backgroundY + BASE_BACKGROUND_HEIGHT)
offeredPokemonModel?.baseScale = scale
offeredPokemonModel?.offsetY = scaleOffsetY
offeredPokemonModel?.render(context, mouseX, mouseY, delta)
offeredPokemonModels.forEachIndexed { i, model ->
val posAndScale = getModelPositionAndScale(i, offeredPokemons.size, x + 70, y + 30)
val originalScale = posAndScale.second
model.baseScale = if (isShrinking) (originalScale / PORTRAIT_SCALE) * scale else originalScale
model.offsetY = if (isShrinking) scaleOffsetY else PORTRAIT_MODEL_OFFSET_Y
val startCenterX = posAndScale.first.first + (PORTRAIT_SIZE / 2.0)
val startCenterY = posAndScale.first.second + (PORTRAIT_SIZE / 2.0)
context.pose().pushPose()
context.pose().translate((myCenterXDest - startCenterX) * shrinkPercentage, (myCenterYDest - startCenterY) * shrinkPercentage, 0.0)
model.render(context, mouseX, mouseY, delta)
context.pose().popPose()
}
opposingOfferedPokemonModels.forEachIndexed { i, model ->
val posAndScale = getModelPositionAndScale(i, opposingPokemons.size, x + 145, y + 30)
val originalScale = posAndScale.second
model.baseScale = if (isShrinking) (originalScale / PORTRAIT_SCALE) * scale else originalScale
model.offsetY = if (isShrinking) scaleOffsetY else PORTRAIT_MODEL_OFFSET_Y
val startCenterX = posAndScale.first.first + (PORTRAIT_SIZE / 2.0)
val startCenterY = posAndScale.first.second + (PORTRAIT_SIZE / 2.0)
context.pose().pushPose()
context.pose().translate((opCenterXDest - startCenterX) * shrinkPercentage, (opCenterYDest - startCenterY) * shrinkPercentage, 0.0)
model.render(context, mouseX, mouseY, delta)
context.pose().popPose()
}
opposingOfferedPokemonModel?.baseScale = scale
opposingOfferedPokemonModel?.offsetY = scaleOffsetY
opposingOfferedPokemonModel?.render(context, mouseX, mouseY, delta)
context.disableScissor()
}
@@ -430,46 +341,8 @@ class TradeGUI(
renderInfoLabels(context, x, y)
children().filterIsInstance<PartySlot>().forEach { slot ->
if (slot.isHovered(mouseX, mouseY)) {
val hoveredId = slot.pokemon?.pokemonId
if (slot.isOpposing && slot.hasSelected()) {
opposingPokemons.find { it.uuid == hoveredId }?.let { opposingOfferedPokemon = it }
} else if (!slot.isOpposing) {
val matchingModel = offeredPokemons.find { it.uuid == hoveredId }
if (matchingModel != null) {
offeredPokemon = matchingModel
} else {
val realPokemon = com.cobblemon.mod.common.client.CobblemonClient.storage.party.find { it?.uuid == hoveredId }
if (realPokemon != null) {
offeredPokemon = realPokemon
}
}
}
}
}
val currentOffered = offeredPokemon
if (currentOffered != null) {
renderPokemonInfo(currentOffered, false, context, x, y, mouseX, mouseY)
if (::offeredPokemonMarkings.isInitialized) {
offeredPokemonMarkings.visible = true
if (offeredPokemonMarkings.pokemon != currentOffered) offeredPokemonMarkings.setActivePokemon(currentOffered)
}
} else {
if (::offeredPokemonMarkings.isInitialized) offeredPokemonMarkings.visible = false
}
val currentOpposing = opposingOfferedPokemon
if (currentOpposing != null) {
renderPokemonInfo(currentOpposing, true, context, x, y, mouseX, mouseY)
if (::opposingOfferedPokemonMarkings.isInitialized) {
opposingOfferedPokemonMarkings.visible = true
if (opposingOfferedPokemonMarkings.pokemon != currentOpposing) opposingOfferedPokemonMarkings.setActivePokemon(currentOpposing)
}
} else {
if (::opposingOfferedPokemonMarkings.isInitialized) opposingOfferedPokemonMarkings.visible = false
}
renderPokemonInfo(offeredPokemon, false, context, x, y, mouseX, mouseY)
renderPokemonInfo(opposingOfferedPokemon, true, context, x, y, mouseX, mouseY)
if (trade.acceptedOppositeOffer) {
blitk(
@@ -558,25 +431,19 @@ class TradeGUI(
super.render(context, mouseX, mouseY, delta)
val ttOffered = offeredPokemon
if (ttOffered != null) {
// Item Tooltip
if (!ttOffered.heldItemNoCopy().isEmpty) {
val itemX = x + 50
val itemY = y + 125
val itemHovered = mouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && mouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
if (itemHovered) context.renderTooltip(Minecraft.getInstance().font, ttOffered.heldItemNoCopy(), mouseX, mouseY)
}
// Item Tooltip
if (offeredPokemon != null && !offeredPokemon!!.heldItemNoCopy().isEmpty) {
val itemX = x + 50
val itemY = y + 125
val itemHovered = mouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && mouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
if (itemHovered) context.renderTooltip(Minecraft.getInstance().font, offeredPokemon!!.heldItemNoCopy(), mouseX, mouseY)
}
val ttOpposing = opposingOfferedPokemon
if (ttOpposing != null) {
if (!ttOpposing.heldItemNoCopy().isEmpty) {
val itemX = x + 227
val itemY = y + 125
val itemHovered = mouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && mouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
if (itemHovered) context.renderTooltip(Minecraft.getInstance().font, ttOpposing.heldItemNoCopy(), mouseX, mouseY)
}
if (opposingOfferedPokemon != null && !opposingOfferedPokemon!!.heldItemNoCopy().isEmpty) {
val itemX = x + 227
val itemY = y + 125
val itemHovered = mouseX.toFloat() in (itemX.toFloat()..(itemX.toFloat() + 16)) && mouseY.toFloat() in (itemY.toFloat()..(itemY.toFloat() + 16))
if (itemHovered) context.renderTooltip(Minecraft.getInstance().font, opposingOfferedPokemon!!.heldItemNoCopy(), mouseX, mouseY)
}
}
@@ -613,13 +480,11 @@ class TradeGUI(
}
if (tradeAnimationProgress == (MAX_TRADE_PROGRESS + CRY_BUFFER)) {
offeredPokemonModels.forEach {
it.state.activeAnimations.clear()
it.state.addFirstAnimation(setOf("cry"))
}
opposingOfferedPokemonModels.forEach {
it.state.activeAnimations.clear()
it.state.addFirstAnimation(setOf("cry"))
if (offeredPokemonModel !== null && opposingOfferedPokemonModel !== null) {
offeredPokemonModel!!.state.activeAnimations.clear()
offeredPokemonModel!!.state.addFirstAnimation(setOf("cry"))
opposingOfferedPokemonModel!!.state.activeAnimations.clear()
opposingOfferedPokemonModel!!.state.addFirstAnimation(setOf("cry"))
}
}
@@ -650,140 +515,41 @@ class TradeGUI(
override fun renderMenuBackground(context: GuiGraphics) {}
private fun setOfferedPokemon(pokemonList: List<Pokemon>, isOpposing: Boolean = false) {
private fun setOfferedPokemon(pokemon: Pokemon?, isOpposing: Boolean = false) {
protectiveTicks = 20
if (isOpposing) {
val wasEmpty = opposingPokemons.isEmpty()
val currentViewedUuid = if (opposingGridMode) null else opposingOfferedPokemon?.uuid
opposingPokemons.clear()
opposingPokemons.addAll(pokemonList)
val matchingPokemon = opposingPokemons.find { it.uuid == currentViewedUuid }
if (matchingPokemon != null) {
opposingOfferedPokemon = matchingPokemon
if (::opposingOfferedPokemonMarkings.isInitialized) opposingOfferedPokemonMarkings.setActivePokemon(opposingOfferedPokemon)
} else {
opposingOfferedPokemon = opposingPokemons.lastOrNull()
if (::opposingOfferedPokemonMarkings.isInitialized) opposingOfferedPokemonMarkings.setActivePokemon(opposingOfferedPokemon)
if (wasEmpty && opposingOfferedPokemon != null) {
opposingGridMode = false
} else if (!opposingGridMode) {
opposingGridMode = true
}
}
trade.acceptedOppositeOffer = false
} else {
val wasEmpty = offeredPokemons.isEmpty()
val currentViewedUuid = if (myGridMode) null else offeredPokemon?.uuid
offeredPokemons.clear()
offeredPokemons.addAll(pokemonList)
val matchingPokemon = offeredPokemons.find { it.uuid == currentViewedUuid }
if (matchingPokemon != null) {
offeredPokemon = matchingPokemon
if (::offeredPokemonMarkings.isInitialized) offeredPokemonMarkings.setActivePokemon(offeredPokemon)
} else {
offeredPokemon = offeredPokemons.lastOrNull()
if (::offeredPokemonMarkings.isInitialized) offeredPokemonMarkings.setActivePokemon(offeredPokemon)
if (wasEmpty && offeredPokemon != null) {
myGridMode = false
} else if (!myGridMode) {
myGridMode = true
}
}
}
rebuildSelectedModels(isOpposing)
}
private fun rebuildSelectedModels(isOpposing: Boolean) {
val x = (width - BASE_WIDTH) / 2
val y = (height - BASE_HEIGHT) / 2
if (isOpposing) {
opposingOfferedPokemonModels.clear()
val total = opposingPokemons.size
opposingPokemons.forEachIndexed { i, pk ->
val (pos, currentScale) = getModelPositionAndScale(i, total, x + 145, y + 30)
opposingOfferedPokemonModels.add(ModelWidget(
pX = pos.first, pY = pos.second,
pWidth = PORTRAIT_SIZE, pHeight = PORTRAIT_SIZE,
pokemon = pk.asRenderablePokemon(),
baseScale = currentScale,
rotationY = 35F,
offsetY = PORTRAIT_MODEL_OFFSET_Y
))
}
opposingOfferedPokemon = pokemon
opposingOfferedPokemonModel = if (pokemon != null) ModelWidget(
pX = x + 145,
pY = y + 30,
pWidth = PORTRAIT_SIZE,
pHeight = PORTRAIT_SIZE,
pokemon = pokemon.asRenderablePokemon(),
baseScale = PORTRAIT_SCALE,
rotationY = 35F,
offsetY = PORTRAIT_MODEL_OFFSET_Y
) else null
if (::opposingOfferedPokemonMarkings.isInitialized) opposingOfferedPokemonMarkings.setActivePokemon(opposingOfferedPokemon)
trade.acceptedOppositeOffer = false
} else {
offeredPokemonModels.clear()
val total = offeredPokemons.size
offeredPokemons.forEachIndexed { i, pk ->
val (pos, currentScale) = getModelPositionAndScale(i, total, x + 70, y + 30)
offeredPokemonModels.add(ModelWidget(
pX = pos.first, pY = pos.second,
pWidth = PORTRAIT_SIZE, pHeight = PORTRAIT_SIZE,
pokemon = pk.asRenderablePokemon(),
baseScale = currentScale,
rotationY = 325F,
offsetY = PORTRAIT_MODEL_OFFSET_Y
))
}
offeredPokemon = pokemon
offeredPokemonModel = if (pokemon != null) ModelWidget(
pX = x + 70,
pY = y + 30,
pWidth = PORTRAIT_SIZE,
pHeight = PORTRAIT_SIZE,
pokemon = pokemon.asRenderablePokemon(),
baseScale = PORTRAIT_SCALE,
rotationY = 325F,
offsetY = PORTRAIT_MODEL_OFFSET_Y
) else null
if (::offeredPokemonMarkings.isInitialized) offeredPokemonMarkings.setActivePokemon(offeredPokemon)
}
}
private fun getModelPositionAndScale(index: Int, total: Int, baseX: Int, baseY: Int): Pair<Pair<Int, Int>, Float> {
val scale = when (total) {
1 -> PORTRAIT_SCALE
2 -> PORTRAIT_SCALE * 0.75f
3 -> PORTRAIT_SCALE * 0.65f
4 -> PORTRAIT_SCALE * 0.55f
else -> PORTRAIT_SCALE * 0.5f
}
if (total <= 1) {
return Pair(Pair(baseX, baseY), scale)
}
val rowLength1 = when (total) {
2, 3, 4 -> 2
else -> 3
}
val rowLength2 = total - rowLength1
val isBottomRow = index >= rowLength1
val row = if (isBottomRow) 1 else 0
val col = if (isBottomRow) index - rowLength1 else index
val currentRowLength = if (isBottomRow) rowLength2 else rowLength1
val colSpacing = when (total) {
2 -> 35
3 -> 30
4 -> 25
else -> 23
}
val rowSpacing = when (total) {
2, 3 -> 30
4 -> 28
else -> 25
}
val totalWidth = (currentRowLength - 1) * colSpacing
val startX = baseX - (totalWidth / 2)
val totalHeight = if (rowLength2 > 0) rowSpacing else 0
var startY = baseY + 12 - (totalHeight / 2)
if (total >= 4) {
startY += 8
}
val posX = startX + (col * colSpacing)
val posY = startY + (row * rowSpacing)
return Pair(Pair(posX, posY), scale)
}
private fun playSound(soundEvent: SoundEvent): SoundInstance {
val soundInstance = SimpleSoundInstance.forUI(soundEvent, 1.0F)
Minecraft.getInstance().soundManager.play(soundInstance)
@@ -791,10 +557,10 @@ class TradeGUI(
}
private fun cancelTradeSound() {
if (tradeSoundInstance != null) Minecraft.getInstance().soundManager.stop(tradeSoundInstance!!)
if (tradeSoundInstance !== null) Minecraft.getInstance().soundManager.stop(tradeSoundInstance)
}
public fun renderPokemonInfo(pokemon: Pokemon?, isOpposing: Boolean, context: GuiGraphics, x: Int, y: Int, mouseX: Int, mouseY: Int) {
private fun renderPokemonInfo(pokemon: Pokemon?, isOpposing: Boolean, context: GuiGraphics, x: Int, y: Int, mouseX: Int, mouseY: Int) {
if (pokemon != null) {
val matrices = context.pose()
// Level
@@ -1281,4 +1047,4 @@ class TradeGUI(
scale = SCALE
)
}
}
}
@@ -1,30 +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.net.bag
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.item.bag.CobblemonBagMenu
import com.cobblemon.mod.common.net.messages.client.bag.UpdateBagMenuDataPacket
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
object UpdateBagMenuDataHandler : ServerNetworkPacketHandler<UpdateBagMenuDataPacket> {
override fun handle(packet: UpdateBagMenuDataPacket, server: MinecraftServer, player: ServerPlayer) {
if (player.containerMenu !is CobblemonBagMenu) {
Cobblemon.LOGGER.debug("Player {} interacted with invalid menu {}", player, player.containerMenu)
return
}
val menu = player.containerMenu as? CobblemonBagMenu ?: return
menu.currentlySelectedCategory = packet.categoryId
menu.scroll = packet.scroll
menu.setupSlotsBasedOnContent()
}
}
@@ -1,28 +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.net.bag
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.item.bag.CobblemonBagMenu
import com.cobblemon.mod.common.net.messages.client.bag.UseItemOnPokemonFromBagPacket
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
object UseItemOnPokemonFromBagHandler: ServerNetworkPacketHandler<UseItemOnPokemonFromBagPacket> {
override fun handle(packet: UseItemOnPokemonFromBagPacket, server: MinecraftServer, player: ServerPlayer) {
if (player.containerMenu !is CobblemonBagMenu) {
Cobblemon.LOGGER.debug("Player {} interacted with invalid menu {}", player, player.containerMenu)
return
}
val menu = player.containerMenu as? CobblemonBagMenu ?: return
menu.useHeldItemOnPokemon(packet.partySlot)
}
}
@@ -15,9 +15,9 @@ import net.minecraft.client.Minecraft
object TradeAcceptanceChangedHandler : ClientNetworkPacketHandler<TradeAcceptanceChangedPacket> {
override fun handle(packet: TradeAcceptanceChangedPacket, client: Minecraft) {
if (CobblemonClient.trade?.myOffer?.get()?.any { it.uuid == packet.pokemonId } == true) {
if (CobblemonClient.trade?.myOffer?.get()?.uuid == packet.pokemonId) {
CobblemonClient.trade!!.oppositeAcceptedMyOffer.set(packet.accepted)
} else if (CobblemonClient.trade?.oppositeOffer?.get()?.any { it.uuid == packet.pokemonId } == true) {
} else if (CobblemonClient.trade?.oppositeOffer?.get()?.uuid == packet.pokemonId) {
CobblemonClient.trade!!.acceptedOppositeOffer = packet.accepted
}
}
@@ -16,6 +16,6 @@ import net.minecraft.client.Minecraft
object TradeCompletedHandler : ClientNetworkPacketHandler<TradeCompletedPacket> {
override fun handle(packet: TradeCompletedPacket, client: Minecraft) {
val trade = CobblemonClient.trade ?: return
trade.completedEmitter.emit(packet.pokemonIds1 to packet.pokemonIds2)
trade.completedEmitter.emit(packet.pokemonId1 to packet.pokemonId2)
}
}
@@ -20,7 +20,7 @@ import net.minecraft.client.Minecraft
object TradeStartedHandler : ClientNetworkPacketHandler<TradeStartedPacket> {
override fun handle(packet: TradeStartedPacket, client: Minecraft) {
Cobblemon.LOGGER.info("Trade started with {}", packet.traderId)
Cobblemon.LOGGER.error("handle trade start from: " + packet.traderId)
val trade = ClientTrade()
CobblemonClient.trade = trade
Minecraft.getInstance().setScreen(
@@ -18,9 +18,9 @@ object TradeUpdatedHandler : ClientNetworkPacketHandler<TradeUpdatedPacket> {
val trade = CobblemonClient.trade ?: return
if (packet.playerId == Minecraft.getInstance().player?.uuid) {
trade.myOffer.set(packet.pokemons)
trade.myOffer.set(packet.pokemon)
} else {
trade.oppositeOffer.set(packet.pokemons)
trade.oppositeOffer.set(packet.pokemon)
}
trade.oppositeAcceptedMyOffer.set(false)
trade.acceptedOppositeOffer = false
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.layer
import com.cobblemon.mod.common.client.CobblemonBakingOverrides
import com.cobblemon.mod.common.item.bag.CobblemonBagItem
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.math.Axis
import net.minecraft.client.Minecraft
import net.minecraft.client.model.PlayerModel
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.entity.RenderLayerParent
import net.minecraft.client.renderer.entity.layers.RenderLayer
import net.minecraft.client.renderer.texture.OverlayTexture
import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemDisplayContext
class CobblemonBagRenderer<T : Player>(renderLayerParent: RenderLayerParent<T, PlayerModel<T>>): RenderLayer<T, PlayerModel<T>>(renderLayerParent) {
override fun render(
poseStack: PoseStack,
bufferSource: MultiBufferSource,
packedLight: Int,
player: T,
limbSwing: Float,
limbSwingAmount: Float,
partialTick: Float,
ageInTicks: Float,
netHeadYaw: Float,
headPitch: Float
) {
val bagItem = player.getItemBySlot(EquipmentSlot.CHEST)
if (bagItem.item !is CobblemonBagItem) return
val model = CobblemonBakingOverrides.bagModels[bagItem.item]?.getModel() ?: return
player.level().profiler.push("cobblemon_bag_render")
poseStack.pushPose()
parentModel.body.translateAndRotate(poseStack)
poseStack.rotateAround(Axis.ZP.rotationDegrees(180F), 0F, 1F, 0F)
poseStack.translate(0.0, 1.0, 0.0)
Minecraft.getInstance().itemRenderer.render(
bagItem,
ItemDisplayContext.FIXED,
false,
poseStack,
bufferSource,
packedLight,
OverlayTexture.NO_OVERLAY,
model
)
poseStack.popPose()
player.level().profiler.pop()
}
}
@@ -14,12 +14,12 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import java.util.UUID
class ClientTrade {
var myOffer = SettableObservable<List<Pokemon>>(emptyList())
var oppositeOffer = SettableObservable<List<Pokemon>>(emptyList())
var myOffer = SettableObservable<Pokemon?>(null)
var oppositeOffer = SettableObservable<Pokemon?>(null)
var tradeProcessing = SettableObservable(Pair(false, false))
var oppositeAcceptedMyOffer = SettableObservable(false)
var acceptedOppositeOffer = false
var completedEmitter = SimpleObservable<Pair<List<UUID>, List<UUID>>>()
var completedEmitter = SimpleObservable<Pair<UUID, UUID>>()
var cancelEmitter = SimpleObservable<Unit>()
}
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.data
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.bag.BagCategories
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.api.data.DataProvider
@@ -121,7 +120,6 @@ object CobblemonDataProvider : DataProvider {
this.register(SpawnBaitEffects, reloadable = false)
this.register(CobblemonRideSettings, reloadable = true)
this.register(TechnicalMachines, reloadable = false)
this.register(BagCategories, reloadable = false)
SpawnBait.Effects.setupEffects()
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
@@ -160,4 +160,5 @@ class CobblemonChestBoatEntity(entityType: EntityType<CobblemonChestBoatEntity>,
private const val INVENTORY_SLOTS = 27
}
}
@@ -117,6 +117,7 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.component.DataComponents
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtOps
import net.minecraft.nbt.NbtUtils
@@ -132,6 +133,7 @@ import net.minecraft.network.protocol.game.DebugPackets
import net.minecraft.network.syncher.EntityDataAccessor
import net.minecraft.network.syncher.EntityDataSerializers
import net.minecraft.network.syncher.SynchedEntityData
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerEntity
import net.minecraft.server.level.ServerLevel
@@ -173,6 +175,7 @@ import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.level.material.EmptyFluid
import net.minecraft.world.level.material.FluidState
import net.minecraft.world.level.pathfinder.PathType
import net.minecraft.world.level.storage.loot.LootTable
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.util.*
@@ -242,6 +245,12 @@ open class PokemonEntity(
override val schedulingTracker = SchedulingTracker()
override fun getDefaultLootTable(): ResourceKey<LootTable?>? {
println(cobblemonResource("pokemon/${this.pokemon.species.resourceIdentifier.path}"))
// return ResourceKey.create(Registries.LOOT_TABLE, )
return super.getDefaultLootTable()
}
val form: FormData
get() = pokemon.form
val behaviour: FormPokemonBehaviour
@@ -2744,9 +2753,4 @@ open class PokemonEntity(
}
fun hasRider() = this.passengers.any { it is LivingEntity }
override fun playStepSound(pos: BlockPos, state: BlockState) {
if (this.pokemon.species.silenceStepSounds) return
super.playStepSound(pos, state)
}
}
}
@@ -31,7 +31,6 @@ import net.minecraft.world.item.BlockItem
import com.cobblemon.mod.common.platform.events.ServerPlayerEvent
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreTypes
import com.cobblemon.mod.common.item.GemItem
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.effectiveName
import com.cobblemon.mod.common.util.getPlayer
@@ -165,21 +164,26 @@ object AdvancementHandler : EventHandler {
}
fun onTradeCompleted(event : TradeEvent.Post) {
onTradeCompleted(event.tradeParticipant1Pokemon, event.tradeParticipant2Pokemon)
onTradeCompleted(event.tradeParticipant2Pokemon, event.tradeParticipant1Pokemon)
}
private fun onTradeCompleted(received: List<Pokemon>, traded: List<Pokemon>) {
val player = received.firstOrNull()?.getOwnerPlayer() ?: return
received.forEach { receivedPokemon ->
traded.forEach { tradedPokemon -> CobblemonCriteria.TRADE_POKEMON.trigger(player, TradePokemonContext(tradedPokemon, receivedPokemon)) }
val player1 = event.tradeParticipant1Pokemon.getOwnerPlayer()
val player2 = event.tradeParticipant2Pokemon.getOwnerPlayer()
if (player1 != null) {
CobblemonCriteria.TRADE_POKEMON.trigger(player1, TradePokemonContext(event.tradeParticipant1Pokemon, event.tradeParticipant2Pokemon))
val playerData = Cobblemon.playerDataManager.getGenericData(player1)
val advancementData = playerData.advancementData
advancementData.updateTotalTradedCount()
advancementData.updateAspectsCollected(player1, event.tradeParticipant2Pokemon)
CobblemonCriteria.COLLECT_ASPECT.trigger(player1, advancementData.aspectsCollected)
Cobblemon.playerDataManager.saveSingle(playerData, PlayerInstancedDataStoreTypes.GENERAL)
}
if (player2 != null) {
CobblemonCriteria.TRADE_POKEMON.trigger(player2, TradePokemonContext(event.tradeParticipant2Pokemon, event.tradeParticipant1Pokemon))
val playerData = Cobblemon.playerDataManager.getGenericData(player2)
val advancementData = playerData.advancementData
advancementData.updateTotalTradedCount()
advancementData.updateAspectsCollected(player2, event.tradeParticipant1Pokemon)
CobblemonCriteria.COLLECT_ASPECT.trigger(player2, advancementData.aspectsCollected)
Cobblemon.playerDataManager.saveSingle(playerData, PlayerInstancedDataStoreTypes.GENERAL)
}
val playerData = Cobblemon.playerDataManager.getGenericData(player)
val advancementData = playerData.advancementData
advancementData.updateTotalTradedCount()
received.forEach { advancementData.updateAspectsCollected(player, it) }
CobblemonCriteria.COLLECT_ASPECT.trigger(player, advancementData.aspectsCollected)
Cobblemon.playerDataManager.saveSingle(playerData, PlayerInstancedDataStoreTypes.GENERAL)
}
/**
@@ -110,8 +110,8 @@ object StatHandler : EventHandler {
}
fun onTradeCompleted(event : TradeEvent.Post) {
event.tradeParticipant1Pokemon.firstOrNull()?.getOwnerPlayer()?.awardStat(getStat(Cobblemon.statistics.TRADED))
event.tradeParticipant2Pokemon.firstOrNull()?.getOwnerPlayer()?.awardStat(getStat(Cobblemon.statistics.TRADED))
event.tradeParticipant1Pokemon.getOwnerPlayer()?.awardStat(getStat(Cobblemon.statistics.TRADED))
event.tradeParticipant2Pokemon.getOwnerPlayer()?.awardStat(getStat(Cobblemon.statistics.TRADED))
}
fun onFossilRevived(event : FossilRevivedEvent) {
@@ -1,99 +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.item.bag
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.world.Container
import net.minecraft.world.ContainerHelper
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import kotlin.math.min
class CobblemonBagContainer: Container {
val items: MutableList<ItemStack> = mutableListOf()
override fun getContainerSize(): Int {
return items.size
}
override fun getItem(slot: Int): ItemStack {
if (slot >= items.size) return ItemStack.EMPTY
return items[slot]
}
override fun isEmpty(): Boolean {
return items.isEmpty()
}
override fun removeItem(slot: Int, amount: Int): ItemStack {
if (slot >= items.size) return ItemStack.EMPTY
val itemStack = items[slot].split(amount)
if (items[slot].isEmpty) {
items.removeAt(slot)
}
return itemStack
}
override fun removeItemNoUpdate(slot: Int): ItemStack { return ItemStack.EMPTY }
override fun clearContent() {
items.clear()
setChanged()
}
override fun setChanged() {
}
override fun setItem(slot: Int, stack: ItemStack) {} // Obsolete
override fun stillValid(player: Player): Boolean {
return true
}
override fun getMaxStackSize(): Int {
return 99999
}
fun fromTag(tag: ListTag, levelRegistry: HolderLookup.Provider) {
items.clear()
tag.forEach {
val compoundTag = it as CompoundTag
val count = compoundTag.getInt("count")
compoundTag.putInt("count", 1)
val item = ItemStack.parse(levelRegistry, it)
item.ifPresent { theItem ->
theItem.count = count
items.add(theItem)
}
}
}
fun createTag(levelRegistry: HolderLookup.Provider): ListTag {
val tag = ListTag()
items.forEach {
val fakeItem = it.copyWithCount(1)
val compoundTag = fakeItem.save(levelRegistry) as CompoundTag
compoundTag.putInt("count", it.count) // ItemStack does not save count above 99 for some reason, so we save it ourselves
tag.add(compoundTag)
}
return tag
}
fun dropAll(player: Player) {
items.forEach {
player.drop(it, true, false)
}
items.clear()
}
}
@@ -1,54 +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.item.bag
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.item.CobblemonItem
import com.cobblemon.mod.common.bag.BagEntity
import net.minecraft.client.Minecraft
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.core.Holder
import net.minecraft.network.chat.Component
import net.minecraft.sounds.SoundEvent
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResultHolder
import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.Equipable
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
class CobblemonBagItem: CobblemonItem(Properties().stacksTo(1)), MenuProvider, Equipable {
override fun use(level: Level, player: Player, usedHand: InteractionHand): InteractionResultHolder<ItemStack?> {
val itemStack = player.getItemInHand(usedHand)
player.openMenu(this)
return InteractionResultHolder.success(itemStack)
}
override fun createMenu(i: Int, inventory: Inventory, player: Player): AbstractContainerMenu {
val bagEntity = (player as? BagEntity)
val container = bagEntity?.`cobblemon$getBagContainer`() ?: CobblemonBagContainer()
return CobblemonBagMenu(i, inventory, container)
}
override fun getDisplayName(): Component? {
return Component.translatable("cobblemon.container.bag")
}
override fun getEquipmentSlot(): EquipmentSlot = EquipmentSlot.CHEST
override fun getEquipSound(): Holder<SoundEvent?>? {
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.ITEM_BAG_EQUIP, 1.0F))
return null
}
}
@@ -1,428 +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.item.bag
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonMenuType
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.PokemonInteractContext
import com.cobblemon.mod.common.api.bag.BagCategories
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.util.isInBattle
import net.minecraft.CrashReport
import net.minecraft.ReportedException
import net.minecraft.client.Minecraft
import net.minecraft.client.resources.sounds.SimpleSoundInstance
import net.minecraft.core.NonNullList
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvent
import net.minecraft.world.InteractionResult
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.ClickAction
import net.minecraft.world.inventory.ClickType
import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.ItemStack
import kotlin.math.ceil
import kotlin.math.max
import kotlin.math.min
class CobblemonBagMenu: AbstractContainerMenu {
companion object {
val BAG_SLOTS = 0..31
private val PARTY_SLOTS = 32..37
private val INVENTORY_SLOTS = 38..64
private val HOTBAR_SLOTS = 65..73
}
private val playerInventory: Inventory
private val bagContainer: CobblemonBagContainer
private val partyContainer: SimpleContainer
private var serverParty: PartyStore? = null
var currentlySelectedCategory = -1
var scroll = 0
var maxScroll = 0
var categoryItemCounts = mutableListOf<Int>()
constructor(containerId: Int, playerInventory: Inventory): super(CobblemonMenuType.COBBLEMON_BAG, containerId) {
this.playerInventory = playerInventory
this.bagContainer = CobblemonBagContainer()
this.partyContainer = SimpleContainer(6)
for (i in 0..<BagCategories.getOrderedCategoriesList().size) { //Pre-init so Screen does not crash
categoryItemCounts.add(0)
}
initializeSlots(playerInventory)
}
constructor(containerId: Int, playerInventory: Inventory, bagContainer: CobblemonBagContainer): super(CobblemonMenuType.COBBLEMON_BAG, containerId) {
this.playerInventory = playerInventory
this.bagContainer = bagContainer
this.partyContainer = SimpleContainer(6)
this.serverParty = Cobblemon.storage.getParty(playerInventory.player as ServerPlayer)
initializeSlots(playerInventory)
setupSlotsBasedOnContent()
calculateCategoriesItemCounts()
}
private fun initializeSlots(playerInventory: Inventory) {
for ((index, _) in BAG_SLOTS.withIndex()) {
val i = index / 8
val j = index % 8
addSlot(CobblemonBagSlot(bagContainer, -1, 81 + j * 18, 50 + i * 18))
}
for ((index, _) in PARTY_SLOTS.withIndex()) {
val xPos = 46
val yPos = 32 + 33 * index
if (serverParty != null) {
addSlot(CobblemonBagPartySlot(partyContainer, index,
{ serverParty?.get(index) != null },
{ serverParty?.get(index)?.heldItem() ?: ItemStack.EMPTY },
xPos, yPos))
} else {
addSlot(CobblemonBagPartySlot(partyContainer, index,
{ CobblemonClient.storage.party.get(index) != null },
{ CobblemonClient.storage.party.get(index)?.heldItem() ?: ItemStack.EMPTY },
xPos, yPos))
}
}
for ((index, _) in INVENTORY_SLOTS.withIndex()) {
val i = index / 9
val j = index % 9
addSlot(Slot(playerInventory, 9 + index, 81 + j * 18, 142 + i * 18))
}
for ((index, _) in HOTBAR_SLOTS.withIndex()) {
addSlot(Slot(playerInventory, index, 81 + index * 18, 200))
}
}
fun setupSlotsBasedOnContent() {
BAG_SLOTS.forEach {
(getSlot(it) as CobblemonBagSlot).let {
it.simulatedSlot = -1
it.slotOverflowValue = 0
}
}
var slotId = BAG_SLOTS.first - 8 * scroll
bagContainer.items.forEachIndexed { index, itemStack ->
if (currentlySelectedCategory == -1 || BagCategories.getOrderedCategoriesList()[currentlySelectedCategory].itemIsValid(itemStack)) {
val stackCount = ceil(itemStack.count.toFloat() / itemStack.maxStackSize).toInt()
for (i in 0..<stackCount) {
if (slotId in BAG_SLOTS) {
val slot = getSlot(slotId) as CobblemonBagSlot
slot.simulatedSlot = index
slot.slotOverflowValue = i
}
slotId += 1
if (slotId > BAG_SLOTS.last) return@forEachIndexed
}
}
}
updateMaxScroll()
}
fun calculateCategoriesItemCounts() {
val orderedCategories = BagCategories.getOrderedCategoriesList()
categoryItemCounts.clear()
for (i in 0..<orderedCategories.size) {
categoryItemCounts.add(0)
}
bagContainer.items.forEach { itemStack ->
for (i in 0..<orderedCategories.size) {
val category = orderedCategories[i]
if (category.itemIsValid(itemStack)) {
categoryItemCounts[i] += itemStack.count
return@forEach
}
}
}
}
fun changeCategory(categoryId: Int) {
currentlySelectedCategory = categoryId
scroll = 0
setupSlotsBasedOnContent()
}
fun updateMaxScroll() {
var itemCount = 0
bagContainer.items.forEach { itemStack ->
if (currentlySelectedCategory == -1 || BagCategories.getOrderedCategoriesList()[currentlySelectedCategory].itemIsValid(itemStack)) {
itemCount += ceil(itemStack.count.toFloat() / itemStack.maxStackSize).toInt()
}
}
val rowsWithItems = (itemCount - 1) / 8 + 1
maxScroll = max(rowsWithItems - 3, 0)
}
override fun stillValid(player: Player): Boolean {
return true //Add some extra logic like checking for maybe bag item existance
}
override fun sendAllDataToRemote() { //We want to send more info than just the slots
val items = NonNullList.create<ItemStack>()
for (i in PARTY_SLOTS.first..HOTBAR_SLOTS.last) {
this.remoteSlots[i] = this.slots[i].item.copy()
items.add(this.remoteSlots[i].copy())
}
this.remoteCarried = this.carried.copy()
bagContainer.items.forEach {
items.add(it.copy())
}
if (this.synchronizer != null) {
this.synchronizer!!.sendInitialData(this, items, this.remoteCarried, this.remoteDataSlots.toIntArray())
}
}
override fun initializeContents(stateId: Int, items: List<ItemStack>, carried: ItemStack) {
bagContainer.items.clear()
items.forEachIndexed { index, stack ->
val adjustedIndex = index + PARTY_SLOTS.first
if (adjustedIndex in PARTY_SLOTS.first..HOTBAR_SLOTS.last) {
this.slots[adjustedIndex].set(stack)
} else {
bagContainer.items.add(stack)
}
}
this.carried = carried
this.stateId = stateId
setupSlotsBasedOnContent()
calculateCategoriesItemCounts()
}
override fun clicked(slotId: Int, button: Int, clickType: ClickType, player: Player) {
if (slotId in BAG_SLOTS) {
try {
doBagClick(slotId, button, clickType, player)
} catch (exception: Exception) {
val crashReport = CrashReport.forThrowable(exception, "Container click")
val crashReportCategory = crashReport.addCategory("Click info")
crashReportCategory.setDetail("Menu Type") {
if (this.menuType != null) BuiltInRegistries.MENU.getKey(this.menuType!!)
.toString() else "<no type>"
}
crashReportCategory.setDetail("Menu Class") { this.javaClass.getCanonicalName() }
crashReportCategory.setDetail("Slot Count", this.slots.size)
crashReportCategory.setDetail("Slot", slotId)
crashReportCategory.setDetail("Button", button)
crashReportCategory.setDetail("Type", clickType)
throw ReportedException(crashReport)
}
return
} else if (slotId in PARTY_SLOTS) {
onPartySlotClick(slotId, button, clickType, player)
}
super.clicked(slotId, button, clickType, player)
}
// We handle the bag slots completely differently than normal slots, but a lot of default logic is cut
private fun doBagClick(slotId: Int, button: Int, clickType: ClickType, player: Player) {
val slot = (getSlot(slotId) as? CobblemonBagSlot) ?: return
val slotItem = slot.item
if (clickType == ClickType.PICKUP && (button == 0 || button == 1)) {
val primaryButton = if (button == 0) ClickAction.PRIMARY else ClickAction.SECONDARY
val carriedStack = carried
if (carriedStack.isEmpty) {
if (!slotItem.isEmpty) {
val pickupCount = if (primaryButton == ClickAction.PRIMARY) slotItem.count else (slotItem.count + 1) / 2
val removedItemStack = slot.remove(pickupCount)
if (!removedItemStack.isEmpty) {
carried = removedItemStack
slot.onTake(player, removedItemStack)
getAndReduceCategoryCount(removedItemStack)
}
playSound(CobblemonSounds.ITEM_BAG_ITEM_OUT)
setupSlotsBasedOnContent()
}
} else {
val (categoryId, allowedTransfer) = calculateInsertCount(carriedStack)
if (allowedTransfer <= 0) return
val transferCount = if (primaryButton == ClickAction.PRIMARY) min(carriedStack.count, allowedTransfer) else 1
bagContainer.items.forEachIndexed { index, slotStack ->
if (ItemStack.isSameItemSameComponents(carriedStack, slotStack) && !tryItemClickBehaviourOverride(player, primaryButton, CobblemonBagSlot(bagContainer, index, 0, 0), slotStack, carriedStack)
) { // Provide a slot with index equal to the item, as there is not really any 'real' slots
slotStack.grow(transferCount)
carriedStack.shrink(transferCount)
categoryItemCounts[categoryId] += transferCount
playSound(CobblemonSounds.ITEM_BAG_ITEM_IN)
setupSlotsBasedOnContent()
return
}
}
val transferItem = carriedStack.split(transferCount)
bagContainer.items.add(transferItem)
categoryItemCounts[categoryId] += transferCount
playSound(CobblemonSounds.ITEM_BAG_ITEM_IN)
setupSlotsBasedOnContent()
}
} else if (clickType == ClickType.QUICK_MOVE && (button == 0 || button == 1)) {
quickMoveStackFromBag(player, slot)
} else if (clickType == ClickType.CLONE && player.hasInfiniteMaterials() && carried.isEmpty && !slotItem.isEmpty) {
carried = slotItem.copyWithCount(slotItem.maxStackSize)
} else if (clickType == ClickType.THROW && carried.isEmpty && !slotItem.isEmpty) {
val throwCount = if (button == 0) 1 else min(slotItem.count, slotItem.maxStackSize)
val bagSize = bagContainer.items.size
val removedItemStack = slot.remove(throwCount)
player.drop(removedItemStack, true)
playSound(CobblemonSounds.ITEM_BAG_ITEM_OUT)
getAndReduceCategoryCount(removedItemStack)
if (bagSize != bagContainer.items.size) {
setupSlotsBasedOnContent()
}
}
}
//Handle party slot clicked
private fun onPartySlotClick(slotId: Int, button: Int, clickType: ClickType, player: Player) {
val slotItem = getSlot(slotId).item
if (clickType == ClickType.CLONE && player.hasInfiniteMaterials() && carried.isEmpty && !slotItem.isEmpty) {
carried = slotItem.copyWithCount(slotItem.maxStackSize)
} else if (clickType != ClickType.PICKUP) return
if (serverParty == null) return // Client does nothing
if (!carried.isEmpty && (isBlacklisted(carried) || !isWhitelisted(carried))) return //Blacklisted and Whitelisted checks
val index = slotId - PARTY_SLOTS.first
val pokemon = serverParty?.get(index) ?: return
val heldItem = pokemon.heldItem()
if (carried.isEmpty || carried.count <= 1) { // Can Swap/Pickup
val returned = pokemon.swapHeldItem(carried, aiCanDrop = false)
carried = returned
broadcastChanges()
} else if (heldItem.isEmpty) { // Can Placedown
pokemon.swapHeldItem(carried, aiCanDrop = false)
broadcastChanges()
}
}
//Handled only by server
fun useHeldItemOnPokemon(partySlot: Int) {
if (carried.isEmpty) return
val pokemon = serverParty?.get(partySlot) ?: return
val item = carried.item as? PokemonSelectingItem ?: return
val player = playerInventory.player as? ServerPlayer ?: return
if (player.isInBattle()) return
val interaction = item.applyToPokemon(player, carried, pokemon)
if (interaction?.result == InteractionResult.SUCCESS) {
CobblemonCriteria.POKEMON_INTERACT.trigger(player, PokemonInteractContext(pokemon.species.resourceIdentifier, BuiltInRegistries.ITEM.getKey(carried.item)))
broadcastChanges()
}
}
private fun isBlacklisted(stack: ItemStack): Boolean =
BuiltInRegistries.ITEM.getTagOrEmpty(CobblemonItemTags.BLACKLISTED_ITEMS_TO_HOLD).any()
&& stack.`is`(CobblemonItemTags.BLACKLISTED_ITEMS_TO_HOLD)
private fun isWhitelisted(stack: ItemStack): Boolean =
BuiltInRegistries.ITEM.getTagOrEmpty(CobblemonItemTags.WHITELISTED_ITEMS_TO_HOLD).none()
|| stack.`is`(CobblemonItemTags.WHITELISTED_ITEMS_TO_HOLD)
override fun quickMoveStack(player: Player, index: Int): ItemStack { // This will only be called by base inventory
if (index < 0 || index >= slots.size) return ItemStack.EMPTY
val slot = slots[index]
val itemStack = slot.item
val (categoryId, allowedTransfer) = calculateInsertCount(itemStack)
if (allowedTransfer <= 0) return ItemStack.EMPTY
val transferCount = min(itemStack.count, allowedTransfer)
if (slot.hasItem()) {
bagContainer.items.forEach { slotStack ->
if (ItemStack.isSameItemSameComponents(slotStack, itemStack)) {
slotStack.grow(transferCount)
itemStack.shrink(transferCount)
categoryItemCounts[categoryId] += transferCount
playSound(CobblemonSounds.ITEM_BAG_ITEM_IN)
setupSlotsBasedOnContent()
return ItemStack.EMPTY
}
}
bagContainer.items.add(itemStack.split(transferCount))
categoryItemCounts[categoryId] += transferCount
playSound(CobblemonSounds.ITEM_BAG_ITEM_IN)
setupSlotsBasedOnContent()
}
return ItemStack.EMPTY
}
fun quickMoveStackFromBag(player: Player, slot: CobblemonBagSlot) { //Called by bag items
val transferStack = slot.item
val startingCount = transferStack.count
if (moveItemStackTo(transferStack, INVENTORY_SLOTS.first, HOTBAR_SLOTS.last + 1, false)) {
val itemsMoved = startingCount - transferStack.count
getAndReduceCategoryCount(slot.remove(itemsMoved))
playSound(CobblemonSounds.ITEM_BAG_ITEM_OUT)
setupSlotsBasedOnContent()
}
}
fun calculateInsertCount(stack: ItemStack): Pair<Int, Int> {
if (stack.isEmpty) return -1 to 0
BagCategories.getOrderedCategoriesList().forEachIndexed { index, category ->
if (category.itemIsValid(stack)) {
val maxAllowed = max(category.maxCount - categoryItemCounts[index], 0)
return index to min(stack.count, maxAllowed)
}
}
return -1 to 0
}
fun getAndReduceCategoryCount(stack: ItemStack) {
if (stack.isEmpty) return
BagCategories.getOrderedCategoriesList().forEachIndexed { index, category ->
if (category.itemIsValid(stack)) {
categoryItemCounts[index] -= stack.count
return
}
}
}
override fun canTakeItemForPickAll(stack: ItemStack, slot: Slot): Boolean {
return slot.index !in BAG_SLOTS
}
fun playSound(soundEvent: SoundEvent) {
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1.0F))
}
}
@@ -1,37 +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.item.bag
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.ItemStack
class CobblemonBagPartySlot(
container: SimpleContainer,
index: Int,
val activeGetter: () -> Boolean,
val itemGetter: () -> ItemStack,
x: Int,
y: Int
): Slot(container, index, x, y) {
override fun getMaxStackSize(): Int = 1
override fun mayPlace(stack: ItemStack): Boolean = false
override fun mayPickup(player: Player): Boolean = false
override fun getItem(): ItemStack {
return itemGetter.invoke()
}
override fun isActive(): Boolean {
return activeGetter.invoke()
}
}
@@ -1,41 +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.item.bag
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.Slot
import net.minecraft.world.item.ItemStack
import java.util.Optional
import kotlin.math.min
class CobblemonBagSlot(
container: CobblemonBagContainer,
var simulatedSlot: Int, //Cant override base slot variable so it is forever -1
x: Int,
y: Int
): Slot(container, 0, x, y) {
var slotOverflowValue = 0
override fun set(stack: ItemStack) {}
override fun getItem(): ItemStack {
if (simulatedSlot == -1) return ItemStack.EMPTY
val itemStack = container.getItem(simulatedSlot)
val count = min(itemStack.count - itemStack.maxStackSize * slotOverflowValue, itemStack.maxStackSize)
return itemStack.copyWithCount(count)
}
override fun remove(amount: Int): ItemStack {
if (simulatedSlot == -1) return ItemStack.EMPTY
return container.removeItem(simulatedSlot, amount)
}
override fun mayPlace(stack: ItemStack): Boolean = false
override fun mayPickup(player: Player): Boolean = false
}
@@ -945,8 +945,6 @@ object CobblemonItemGroups {
CobblemonItems.pokeBalls.forEach(entries::accept)
CobblemonItems.pokeRods.forEach(entries::accept)
CobblemonItems.pokedexes.forEach(entries::accept)
entries.accept(CobblemonItems.TRAINER_PACK)
entries.accept(CobblemonItems.TRAINER_BAG)
}
private fun blocksInjections(injector: Injector) {
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.item.interactive
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.item.components.FoodComponent
import net.minecraft.network.chat.Component
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
@@ -24,15 +23,10 @@ import net.minecraft.world.level.Level
class PonigiriItem : Item(
Properties().stacksTo(64)
.food(FoodProperties.Builder()
.nutrition(NUTRITION)
.saturationModifier(SATURATION_MODIFIER)
.nutrition(2)
.saturationModifier(0.55f)
.build())
) {
companion object {
const val NUTRITION = 2
const val SATURATION_MODIFIER = 0.55f
}
override fun getName(stack: ItemStack): Component {
val ingredients = stack.get(CobblemonItemComponents.INGREDIENT)
@@ -65,9 +59,4 @@ class PonigiriItem : Item(
override fun getEatingSound(): SoundEvent {
return SoundEvents.GENERIC_EAT
}
fun getFoodValues(stack: ItemStack): Pair<Int, Float> {
val (hunger, saturation) = stack.getOrDefault(CobblemonItemComponents.FOOD, FoodComponent(NUTRITION, SATURATION_MODIFIER))
return hunger to saturation
}
}
}
@@ -0,0 +1,28 @@
package com.cobblemon.mod.common.loot
import com.cobblemon.mod.common.loot.conditions.RequirementLootItemCondition
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
object CobblemonLootItemConditions :
PlatformRegistry<Registry<LootItemConditionType>, ResourceKey<Registry<LootItemConditionType>>, LootItemConditionType>() {
@JvmField
val REQUIREMENT_CONDITION = create(
cobblemonResource("requirement"),
LootItemConditionType(RequirementLootItemCondition.CODEC)
)
fun touch() = Unit
override val registry: Registry<LootItemConditionType>
get() = BuiltInRegistries.LOOT_CONDITION_TYPE
override val resourceKey: ResourceKey<Registry<LootItemConditionType>>
get() = Registries.LOOT_CONDITION_TYPE
}
@@ -0,0 +1,37 @@
package com.cobblemon.mod.common.loot.conditions
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.loot.CobblemonLootItemConditions
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
/**
* Allows for use of a [Requirement] as a [LootItemConditionType]
*/
class RequirementLootItemCondition(
val requirement: Requirement
) : LootItemCondition {
override fun getType(): LootItemConditionType {
return CobblemonLootItemConditions.REQUIREMENT_CONDITION
}
override fun test(t: LootContext): Boolean {
val entity = t.getParamOrNull(LootContextParams.THIS_ENTITY) as? PokemonEntity ?: return false
return requirement.check(entity.pokemon)
}
companion object {
val CODEC: MapCodec<RequirementLootItemCondition> = RecordCodecBuilder.mapCodec { instance ->
instance.group(
Requirement.CODEC.fieldOf("requirement")
.forGetter(RequirementLootItemCondition::requirement)
).apply(instance, ::RequirementLootItemCondition)
}
}
}
@@ -1,28 +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.net.messages.client.bag
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
class UpdateBagMenuDataPacket(val categoryId: Int, val scroll: Int): NetworkPacket<UpdateBagMenuDataPacket> {
companion object {
val ID = cobblemonResource("update_bag_menu_data")
fun decode(buffer: RegistryFriendlyByteBuf): UpdateBagMenuDataPacket {
return UpdateBagMenuDataPacket(buffer.readInt(), buffer.readInt())
}
}
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeInt(categoryId)
buffer.writeInt(scroll)
}
}
@@ -1,26 +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.net.messages.client.bag
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
class UseItemOnPokemonFromBagPacket(val partySlot: Int): NetworkPacket<UseItemOnPokemonFromBagPacket> {
companion object {
val ID = cobblemonResource("use_item_on_pokemon_from_bag")
fun decode(buffer: RegistryFriendlyByteBuf): UseItemOnPokemonFromBagPacket {
return UseItemOnPokemonFromBagPacket(buffer.readInt())
}
}
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeInt(partySlot)
}
}
@@ -1,32 +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.net.messages.client.data
import com.cobblemon.mod.common.api.bag.BagCategories
import com.cobblemon.mod.common.api.bag.BagCategory
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
class BagCategoriesSyncPacket(categories: List<BagCategory>): DataRegistrySyncPacket<BagCategory, BagCategoriesSyncPacket>(categories) {
companion object {
val ID = cobblemonResource("bag_categories")
fun decode(buffer: RegistryFriendlyByteBuf) = BagCategoriesSyncPacket(emptyList()).apply { decodeBuffer(buffer) }
}
override val id = ID
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: BagCategory) {
entry.encode(buffer)
}
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): BagCategory = BagCategory.decode(buffer)
override fun synchronizeDecoded(entries: Collection<BagCategory>) {
BagCategories.reload(entries.associateBy { it.identifier })
}
}
@@ -23,19 +23,16 @@ import java.util.UUID
* @author Hiroku
* @since March 5th, 2023
*/
class TradeCompletedPacket(val pokemonIds1: List<UUID>, val pokemonIds2: List<UUID>) : NetworkPacket<TradeCompletedPacket> {
class TradeCompletedPacket(val pokemonId1: UUID, val pokemonId2: UUID) : NetworkPacket<TradeCompletedPacket> {
companion object {
val ID = cobblemonResource("trade_completed")
fun decode(buffer: RegistryFriendlyByteBuf) = TradeCompletedPacket(
buffer.readList { it.readUUID() },
buffer.readList { it.readUUID() }
)
fun decode(buffer: RegistryFriendlyByteBuf) = TradeCompletedPacket(buffer.readUUID(), buffer.readUUID())
}
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeCollection(pokemonIds1) { buf, id -> buf.writeUUID(id) }
buffer.writeCollection(pokemonIds2) { buf, id -> buf.writeUUID(id) }
buffer.writeUUID(pokemonId1)
buffer.writeUUID(pokemonId2)
}
}
@@ -12,6 +12,10 @@ import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.UnsplittablePacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readNullable
import com.cobblemon.mod.common.util.readUUID
import com.cobblemon.mod.common.util.writeNullable
import com.cobblemon.mod.common.util.writeUUID
import net.minecraft.network.RegistryFriendlyByteBuf
import java.util.UUID
@@ -23,18 +27,15 @@ import java.util.UUID
* @author Hiroku
* @since March 5th, 2023
*/
class TradeUpdatedPacket(val playerId: UUID, val pokemons: List<Pokemon>) : NetworkPacket<TradeUpdatedPacket>, UnsplittablePacket {
class TradeUpdatedPacket(val playerId: UUID, val pokemon: Pokemon?) : NetworkPacket<TradeUpdatedPacket>, UnsplittablePacket {
companion object {
val ID = cobblemonResource("trade_updated")
fun decode(buffer: RegistryFriendlyByteBuf) = TradeUpdatedPacket(
buffer.readUUID(),
buffer.readList { Pokemon.S2C_CODEC.decode(it as RegistryFriendlyByteBuf) }
)
fun decode(buffer: RegistryFriendlyByteBuf) = TradeUpdatedPacket(buffer.readUUID(), buffer.readNullable { Pokemon.S2C_CODEC.decode(buffer) })
}
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeUUID(playerId)
buffer.writeCollection(pokemons) { buf, pokemon -> Pokemon.S2C_CODEC.encode(buf as RegistryFriendlyByteBuf, pokemon) }
buffer.writeNullable(pokemon) { _, pokemon -> Pokemon.S2C_CODEC.encode(buffer, pokemon) }
}
}
@@ -11,30 +11,26 @@ package com.cobblemon.mod.common.net.messages.server.trade
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.storage.party.PartyPosition
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readList
import com.cobblemon.mod.common.util.readNullable
import com.cobblemon.mod.common.util.readPartyPosition
import com.cobblemon.mod.common.util.readUUID
import com.cobblemon.mod.common.util.writeCollection
import com.cobblemon.mod.common.util.writeNullable
import com.cobblemon.mod.common.util.writePartyPosition
import com.cobblemon.mod.common.util.writeUUID
import net.minecraft.network.RegistryFriendlyByteBuf
import java.util.UUID
class UpdateTradeOfferPacket(val newOffers: List<Pair<UUID, PartyPosition>>): NetworkPacket<UpdateTradeOfferPacket> {
class UpdateTradeOfferPacket(val newOffer: Pair<UUID, PartyPosition>?): NetworkPacket<UpdateTradeOfferPacket> {
companion object {
val ID = cobblemonResource("update_trade_offer")
fun decode(buffer: RegistryFriendlyByteBuf) = UpdateTradeOfferPacket(
buffer.readList { it.readUUID() to it.readPartyPosition() }
)
fun decode(buffer: RegistryFriendlyByteBuf) = UpdateTradeOfferPacket(buffer.readNullable { buffer.readUUID() to buffer.readPartyPosition() })
}
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeCollection(newOffers) { buf, (pokemonId, partyPosition) ->
buf.writeUUID(pokemonId)
buf.writePartyPosition(partyPosition)
buffer.writeNullable(newOffer) { buffer, (pokemonId, partyPosition) ->
buffer.writeUUID(pokemonId)
buffer.writePartyPosition(partyPosition)
}
}
}
@@ -20,7 +20,7 @@ object ChangeTradeAcceptanceHandler : ServerNetworkPacketHandler<ChangeTradeAcce
override fun handle(packet: ChangeTradeAcceptancePacket, server: MinecraftServer, player: ServerPlayer) {
val trade = TradeManager.getActiveTrade(player.uuid) ?: return player.sendPacket(TradeCancelledPacket())
val tradeParticipant = trade.getTradeParticipant(player.uuid)
if (trade.getOpposingOffer(tradeParticipant).pokemon.any { it.uuid == packet.pokemonOfferId }) {
if (trade.getOpposingOffer(tradeParticipant).pokemon?.uuid == packet.pokemonOfferId) {
trade.updateAcceptance(tradeParticipant, packet.newAcceptance)
}
}
@@ -20,7 +20,7 @@ object PerformTradeHandler : ServerNetworkPacketHandler<PerformTradePacket> {
override fun handle(packet: PerformTradePacket, server: MinecraftServer, player: ServerPlayer) {
val trade = TradeManager.getActiveTrade(player.uuid) ?: return player.sendPacket(TradeCancelledPacket())
val tradeParticipant = trade.getTradeParticipant(player.uuid)
if (trade.getOpposingOffer(tradeParticipant).pokemon.any { it.uuid == packet.pokemonOfferId }) {
if (trade.getOpposingOffer(tradeParticipant).pokemon?.uuid == packet.pokemonOfferId) {
trade.performTrade(tradeParticipant)
}
}
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.trade.TradeManager
import com.cobblemon.mod.common.util.party
import net.minecraft.server.MinecraftServer
@@ -22,16 +21,20 @@ object UpdateTradeOfferHandler : ServerNetworkPacketHandler<UpdateTradeOfferPack
override fun handle(packet: UpdateTradeOfferPacket, server: MinecraftServer, player: ServerPlayer) {
val trade = TradeManager.getActiveTrade(player.uuid) ?: return player.sendPacket(CancelTradePacket())
val tradeParticipant = trade.getTradeParticipant(player.uuid)
val newOffers = packet.newOffers
val validPokemons = mutableListOf<Pokemon>()
val party = player.party()
for ((pokemonId, partyPosition) in newOffers) {
val newOffer = packet.newOffer
if (newOffer == null) {
trade.updateOffer(tradeParticipant, null)
} else {
val (pokemonId, partyPosition) = newOffer
val party = player.party()
val pokemon = party[partyPosition]
if (pokemon != null && pokemon.uuid == pokemonId && pokemon.tradeable) {
validPokemons.add(pokemon)
if (pokemon == null || pokemon.uuid != pokemonId) {
return
} else if (!pokemon.tradeable) {
return
} else {
trade.updateOffer(tradeParticipant, pokemon)
}
}
trade.updateOffer(tradeParticipant, validPokemons)
}
}
@@ -173,7 +173,6 @@ class Species : ShowdownIdentifiable {
.addStandardFunctions()
.addSpeciesFunctions(this)
var silenceStepSounds = false
fun initialize() {
Cobblemon.statProvider.provide(this)
@@ -257,7 +256,6 @@ class Species : ShowdownIdentifiable {
}
this.riding.encode(buffer)
buffer.writeBoolean(this.silenceStepSounds)
}
fun decode(buffer: RegistryFriendlyByteBuf) {
@@ -301,7 +299,6 @@ class Species : ShowdownIdentifiable {
}
}
this.riding = RidingProperties.decode(buffer)
this.silenceStepSounds = buffer.readBoolean()
this.initialize()
}
@@ -71,6 +71,7 @@ object CobblemonRequirementAdapter : RequirementAdapter {
this.registerType(OwnerHoldsItemRequirement.ADAPTER_VARIANT, OwnerHoldsItemRequirement::class)
this.registerType(ChanceRequirement.ADAPTER_VARIANT, ChanceRequirement::class)
this.registerType(NegateRequirement.ADAPTER_VARIANT, NegateRequirement::class)
this.registerType(AspectRequirement.ADAPTER_VARIANT, AspectRequirement::class)
}
val gson: Gson by lazy {
@@ -0,0 +1,20 @@
package com.cobblemon.mod.common.pokemon.requirements
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
import com.cobblemon.mod.common.pokemon.Pokemon
/**
* A [Requirement] that checks if a [Pokemon] has a certain aspect.
*
* @property aspect The aspect to check for.
* @author whatsy
*/
class AspectRequirement(val target: String) : Requirement {
override fun check(pokemon: Pokemon): Boolean {
return target in pokemon.aspects
}
companion object {
val ADAPTER_VARIANT = "aspect"
}
}
@@ -19,7 +19,7 @@ class ActiveTrade(val player1: TradeParticipant, val player2: TradeParticipant)
fun getOffer(tradeParticipant: TradeParticipant) = if (tradeParticipant == player1) player1Offer else player2Offer
fun getOpposingOffer(tradeParticipant: TradeParticipant) = if (tradeParticipant == player1) player2Offer else player1Offer
fun updateOffer(tradeParticipant: TradeParticipant, pokemon: List<Pokemon>) {
fun updateOffer(tradeParticipant: TradeParticipant, pokemon: Pokemon?) {
getOffer(tradeParticipant).updateOffer(pokemon)
getOffer(getOppositePlayer(tradeParticipant)).accepted = false
player1.updateOffer(this, tradeParticipant, pokemon)
@@ -30,9 +30,8 @@ class ActiveTrade(val player1: TradeParticipant, val player2: TradeParticipant)
val offer = getOpposingOffer(tradeParticipant)
if (offer.accepted != acceptance) {
offer.accepted = acceptance
val firstId = offer.pokemon.firstOrNull()?.uuid ?: java.util.UUID.randomUUID()
getOppositePlayer(tradeParticipant).changeTradeAcceptance(this, firstId, acceptance)
tradeParticipant.changeTradeAcceptance(this, firstId, acceptance)
getOppositePlayer(tradeParticipant).changeTradeAcceptance(this, offer.pokemon!!.uuid, acceptance)
tradeParticipant.changeTradeAcceptance(this, offer.pokemon!!.uuid, acceptance)
}
if (offer.accepted && getOffer(tradeParticipant).accepted) {
@@ -52,8 +51,8 @@ class ActiveTrade(val player1: TradeParticipant, val player2: TradeParticipant)
activeTrade = this,
player1 = player1,
player2 = player2,
pokemon1 = player1Offer.pokemon,
pokemon2 = player2Offer.pokemon
pokemon1 = player1Offer.pokemon!!,
pokemon2 = player2Offer.pokemon!!
)
}
}
@@ -65,14 +64,12 @@ class ActiveTrade(val player1: TradeParticipant, val player2: TradeParticipant)
}
fun completeTrade() {
val uuids1 = player1Offer.pokemon.map { it.uuid }
val uuids2 = player2Offer.pokemon.map { it.uuid }
player1.completeTrade(this, uuids1, uuids2)
player2.completeTrade(this, uuids2, uuids1)
player1.completeTrade(this, player1Offer.pokemon!!.uuid, player2Offer.pokemon!!.uuid)
player2.completeTrade(this, player2Offer.pokemon!!.uuid, player1Offer.pokemon!!.uuid)
player1Offer.pokemon = emptyList()
player1Offer.pokemon = null
player1Offer.accepted = false
player2Offer.pokemon = emptyList()
player2Offer.pokemon = null
player2Offer.accepted = false
}
}
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.TradeEvent
import com.cobblemon.mod.common.api.interaction.ServerPlayerActionRequest
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.api.text.aqua
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
@@ -102,98 +101,71 @@ object TradeManager : RequestManager<TradeManager.TradeRequest>() {
fun performTrade(
activeTrade: ActiveTrade,
player1: TradeParticipant,
pokemon1: List<Pokemon>,
pokemon1: Pokemon,
player2: TradeParticipant,
pokemon2: List<Pokemon>
pokemon2: Pokemon
) {
val party1 = player1.party
val party2 = player2.party
if (pokemon1.any { it !in party1 } || pokemon2.any { it !in party2 }) {
if (pokemon1 !in party1 || pokemon2 !in party2) {
Cobblemon.LOGGER.warn("Attempted to perform a trade with Pokémon that aren't in the party anymore. Could be attempted duping between ${player1.name} and ${player2.name}")
activeTrade.cancelTrade()
return
}
if (pokemon1.isEmpty() || pokemon2.isEmpty()) {
Cobblemon.LOGGER.warn("Attempted to perform a trade where one side offered no Pokémon between ${player1.name} and ${player2.name}. This should never happen.")
activeTrade.cancelTrade()
return
}
CobblemonEvents.TRADE_EVENT_PRE.postThen(TradeEvent.Pre(player1, pokemon2, player2, pokemon1)) {
val party1 = player1.party
val party2 = player2.party
CobblemonEvents.TRADE_EVENT_PRE.postThen(
TradeEvent.Pre(player1, pokemon2, player2, pokemon1)
) {
val player1Removed = pokemon1.filter { party1.remove(it) }
val player2Removed = pokemon2.filter { party2.remove(it) }
val player1Removed = party1.remove(pokemon1)
val player2Removed = party2.remove(pokemon2)
if (player1Removed.size != pokemon1.size || player2Removed.size != pokemon2.size) {
(pokemon1 - player1Removed.toSet()).forEach {
Cobblemon.LOGGER.warn("Failed to remove traded Pokémon ${it.species.resourceIdentifier} from ${player1.name.string}(${player1.uuid}). Aborting trade with ${player2.name.string}(${player2.uuid}), potential exploit abused.")
if (!player1Removed || !player2Removed) {
if (!player1Removed) {
Cobblemon.LOGGER.warn("Failed to remove traded Pokémon ${pokemon1.species.resourceIdentifier} from ${player1.name.string}(${player1.uuid}). Aborting trade with ${player2.name.string}(${player2.uuid}), potential exploit abused.")
}
(pokemon2 - player2Removed.toSet()).forEach {
Cobblemon.LOGGER.warn("Failed to remove traded Pokémon ${it.species.resourceIdentifier} from ${player2.name.string}(${player2.uuid}). Aborting trade with ${player1.name.string}(${player1.uuid}), potential exploit abused.")
if (!player2Removed) {
Cobblemon.LOGGER.warn("Failed to remove traded Pokémon ${pokemon2.species.resourceIdentifier} from ${player2.name.string}(${player2.uuid}). Aborting trade with ${player1.name.string}(${player1.uuid}), potential exploit abused.")
}
// Revert any changes if one of the removals failed
player1Removed.forEach { party1.add(it) }
player2Removed.forEach { party2.add(it) }
if (player1Removed) party1.add(pokemon1)
if (player2Removed) party2.add(pokemon2)
return@postThen
}
// If player1 is the OT, keep track of the friendship
pokemon1.forEach { it.cacheFriendship(player1.uuid) }
pokemon1.cacheFriendship(player1.uuid)
// If player2 is the OT, keep track of the friendship
pokemon2.forEach { it.cacheFriendship(player2.uuid) }
pokemon2.cacheFriendship(player2.uuid)
// If a Pokémon received by player1 was originally theirs, set the friendship back to what it was at point of trading
pokemon2.forEach {
if (!it.restoreFriendship(player1.uuid)) {
// Otherwise, reset the friendship
it.setFriendship(it.form.baseFriendship)
}
// If pokemon2 was originally player1's, set the friendship back to what it was at point of trading
if ( !pokemon2.restoreFriendship(player1.uuid) ) {
// Otherwise, reset the friendship
pokemon2.setFriendship(pokemon2.form.baseFriendship)
}
// If a Pokémon received by player2 was originally theirs, set the friendship back to what it was at point of trading
pokemon1.forEach {
if (!it.restoreFriendship(player2.uuid)) {
// Otherwise, reset the friendship
it.setFriendship(it.form.baseFriendship)
}
// If pokemon1 was originally player2's, set the friendship back to what it was at point of trading
if ( !pokemon1.restoreFriendship(player2.uuid) ) {
// Otherwise, reset the friendship
pokemon1.setFriendship(pokemon1.form.baseFriendship)
}
pokemon1.forEach { party2.add(it) }
pokemon2.forEach { party1.add(it) }
party2.add(pokemon1)
party1.add(pokemon2)
// Each traded Pokémon may evolve if any of the Pokémon it was traded for satisfies its context.
// Evolutions are resolved before any are applied so one evolving can't invalidate another's context.
(pokemon1.map { it to pokemon2 } + pokemon2.map { it to pokemon1 })
.mapNotNull { (pokemon, tradedFor) ->
pokemon.lockedEvolutions.filterIsInstance<TradeEvolution>()
.firstOrNull { evolution -> tradedFor.any { evolution.testContext(pokemon, it) } && evolution.test(pokemon) }
?.let { pokemon to it }
}
.forEach { (pokemon, evolution) -> evolution.evolve(pokemon) }
pokemon1.lockedEvolutions.filterIsInstance<TradeEvolution>().firstOrNull {
it.attemptEvolution(pokemon1, pokemon2)
}
val compactParty = { party: PartyStore ->
var writeIdx = 0
for (readIdx in 0 until party.size()) {
if (party.get(readIdx) != null) {
if (readIdx != writeIdx) {
party.swap(readIdx, writeIdx)
}
writeIdx++
}
}
pokemon2.lockedEvolutions.filterIsInstance<TradeEvolution>().firstOrNull {
it.attemptEvolution(pokemon2, pokemon1)
}
compactParty(party1)
compactParty(party2)
activeTrade.completeTrade()
CobblemonEvents.TRADE_EVENT_POST.post(
TradeEvent.Post(player1, pokemon2, player2, pokemon1)
)
CobblemonEvents.TRADE_EVENT_POST.post(TradeEvent.Post(player1, pokemon2, player2, pokemon1))
}
}
}
@@ -11,10 +11,10 @@ package com.cobblemon.mod.common.trade
import com.cobblemon.mod.common.pokemon.Pokemon
class TradeOffer {
var pokemon: List<Pokemon> = emptyList()
var pokemon: Pokemon? = null
var accepted = false
fun updateOffer(pokemon: List<Pokemon>) {
fun updateOffer(pokemon: Pokemon?) {
this.pokemon = pokemon
accepted = false
}
@@ -34,7 +34,7 @@ interface TradeParticipant {
*
* If it's null, it means they're no longer offering a Pokémon (so they're redeciding).
*/
fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: List<Pokemon>)
fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: Pokemon?)
/**
* Notifies the participant that the acceptance state for trading with the opponent [Pokemon] with UUID [pokemonId]
@@ -59,7 +59,7 @@ interface TradeParticipant {
fun cancelTrade(trade: ActiveTrade)
/** Notifies the participant that the trade has been completed. The actual Pokémon have already been exchanged. */
fun completeTrade(trade: ActiveTrade, pokemonIds1: List<UUID>, pokemonIds2: List<UUID>)
fun completeTrade(trade: ActiveTrade, pokemonId1: UUID, pokemonId2: UUID)
}
/**
@@ -73,7 +73,7 @@ class PlayerTradeParticipant(val player: ServerPlayer): TradeParticipant {
override val uuid = player.uuid
override val party = player.party()
override fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: List<Pokemon>) {
override fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: Pokemon?) {
player.sendPacket(TradeUpdatedPacket(tradeParticipant.uuid, pokemon))
}
@@ -89,8 +89,8 @@ class PlayerTradeParticipant(val player: ServerPlayer): TradeParticipant {
player.sendPacket(TradeCancelledPacket())
}
override fun completeTrade(trade: ActiveTrade, pokemonIds1: List<UUID>, pokemonIds2: List<UUID>) {
player.sendPacket(TradeCompletedPacket(pokemonIds1, pokemonIds2))
override fun completeTrade(trade: ActiveTrade, pokemonId1: UUID, pokemonId2: UUID) {
player.sendPacket(TradeCompletedPacket(pokemonId1, pokemonId2))
}
}
@@ -109,7 +109,7 @@ class DummyTradeParticipant(val pokemonList: MutableList<Pokemon>) : TradePartic
// Don't need to do any notifying.
}
override fun completeTrade(trade: ActiveTrade, pokemonIds1: List<UUID>, pokemonIds2: List<UUID>) {
override fun completeTrade(trade: ActiveTrade, pokemonId1: UUID, pokemonId2: UUID) {
// Don't need to do any notifying.
}
@@ -121,7 +121,7 @@ class DummyTradeParticipant(val pokemonList: MutableList<Pokemon>) : TradePartic
// React, maybe. Change code and hotswap.
}
override fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: List<Pokemon>) {
override fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: Pokemon?) {
// React, maybe. Change code and hotswap.
}
}
@@ -234,11 +234,11 @@ fun Entity.isDusk(): Boolean {
}
fun Entity.isStandingOn(blocks: Set<String>, depth: Int = 2): Boolean {
for (currentDepth in 0..depth) {
val bellowBlockPos = blockPosBelowThatAffectsMyMovement.below(currentDepth)
for (currentDepth in 1..depth) {
val bellowBlockPos = blockPosition().below(currentDepth)
val blockState = level().getBlockState(bellowBlockPos)
if (blockState.isAir) continue
if (blockState.isAir || !blockState.isCollisionShapeFullBlock(level(), bellowBlockPos)) continue
val elementOrTags = ExtraCodecs.TAG_OR_ELEMENT_ID.listOf().decode(JavaOps.INSTANCE, blocks.toList()).result().get().first
elementOrTags.forEach {
@@ -27,9 +27,5 @@ object CobblemonGameRules {
@JvmField
val HEALERS_HEAL_PC: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("healersHealPC", GameRules.Category.MISC, BooleanRuleInvoker.`cobblemon$create`(false))
@JvmField
val HEALER_SET_SPAWN: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("healersSetSpawn", GameRules.Category.MISC, BooleanRuleInvoker.`cobblemon$create`(false))
@JvmField
val DO_POKEMON_PREDATION: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("doPokemonPredation", GameRules.Category.MOBS, BooleanRuleInvoker.`cobblemon$create`(true))
@JvmField
val BAG_DROP_ITEMS: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("bagDropItems", GameRules.Category.PLAYER, BooleanRuleInvoker.`cobblemon$create`(false))
}
@@ -1815,12 +1815,6 @@
"wings_open": {
"scale": 0
}
},
"timeline": {
"0.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
"0.5": "q.run_molang('cobblemon:stepsound_claw_medium');",
"1.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
"1.5": "q.run_molang('cobblemon:stepsound_claw_medium');"
}
},
"animation.pidgeot.mount_ground_idle": {
@@ -3637,12 +3631,6 @@
"wings_open": {
"scale": 0
}
},
"timeline": {
"0.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
"0.5": "q.run_molang('cobblemon:stepsound_claw_medium');",
"1.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
"1.5": "q.run_molang('cobblemon:stepsound_claw_medium');"
}
},
"animation.pidgeot.ride_ground_walk": {
@@ -1682,12 +1682,6 @@
"1.3333": [10, 9, 0]
}
}
},
"timeline": {
"0.0": "q.run_molang('cobblemon:stepsound_standard_medium');",
"0.4583": "q.run_molang('cobblemon:stepsound_standard_medium');",
"0.6667": "q.run_molang('cobblemon:stepsound_standard_medium');",
"1.125": "q.run_molang('cobblemon:stepsound_standard_medium');"
}
},
"animation.arcanine.ride_ground_walk": {
@@ -2645,12 +2639,6 @@
"chest_fluff_right": {
"rotation": [5, "-22.5+math.cos(q.anim_time*90*8-120)*15", "-math.sin(q.anim_time*90*8-120)*3"]
}
},
"timeline": {
"0.125": "q.run_molang('cobblemon:stepsound_standard_medium');",
"0.2083": "q.run_molang('cobblemon:stepsound_standard_large');",
"0.2917": "q.run_molang('cobblemon:stepsound_standard_medium');",
"0.375": "q.run_molang('cobblemon:stepsound_standard_medium');"
}
},
"animation.arcanine.ride_ground_run": {
@@ -4173,101 +4161,41 @@
"eye_left": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {
"pre": [0, 0, 0],
"post": [-0.1, 0, 0.1]
},
"0.5": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0, 0.1]
},
"1.6667": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
"0.5": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
"1.6667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {
"pre": [0, 0, 0],
"post": [0.1, 0, 0.1]
},
"0.5": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0, 0.1]
},
"1.6667": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
"0.5": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
"1.6667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.5": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"1.6667": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.5": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"1.6667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.5": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"1.6667": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.5": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"1.6667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"jaw": {
@@ -4895,101 +4823,41 @@
"eye_left": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {
"pre": [0, 0, 0],
"post": [-0.1, 0, 0.1]
},
"0.5": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0, 0.1]
},
"1.6667": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
"0.5": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
"1.6667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {
"pre": [0, 0, 0],
"post": [0.1, 0, 0.1]
},
"0.5": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0, 0.1]
},
"1.6667": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
"0.5": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
"1.6667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.5": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"1.6667": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.5": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"1.6667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.1667": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.5": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"1.4167": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"1.6667": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"2.5": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.5": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"1.6667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"jaw": {
@@ -5419,20 +5287,14 @@
"position": {
"0.0": [-0.1, 0, 0.1],
"0.125": [-0.1, 0, 0.1],
"0.1667": {
"pre": [-0.1, 0, 0.1],
"post": [0, 0, 0]
}
"0.1667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0.1, 0, 0.1],
"0.125": [0.1, 0, 0.1],
"0.1667": {
"pre": [0.1, 0, 0.1],
"post": [0, 0, 0]
}
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
}
}
}
@@ -5629,95 +5491,47 @@
"eye_left": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.2, 0, 0.1]
},
"0.3333": {
"pre": [-0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [0.2, 0, 0.1]
},
"0.3333": {
"pre": [0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.2, 0, 0.1]
},
"0.3333": {
"pre": [-0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [0.2, 0, 0.1]
},
"0.3333": {
"pre": [0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_left_hurt": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.3333": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.3333": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_right_hurt": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.3333": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"jaw": {
@@ -6424,95 +6238,47 @@
"eye_left": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.2, 0, 0.1]
},
"0.3333": {
"pre": [-0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eye_right": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [0.2, 0, 0.1]
},
"0.3333": {
"pre": [0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.2, 0, 0.1]
},
"0.3333": {
"pre": [-0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [0.2, 0, 0.1]
},
"0.3333": {
"pre": [0.2, 0, 0.1],
"post": [0, 0, 0]
},
"1.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
}
},
"eyelid_left_hurt": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.3333": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.3333": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_right_hurt": {
"position": {
"0.0": [0, 0, 0],
"0.0417": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.3333": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
}
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"jaw": {
@@ -3150,10 +3150,6 @@
"locator_seat_2": {
"rotation": [45, 0, 0]
}
},
"timeline": {
"0.5": "q.run_molang('cobblemon:stepsound_claw_large');",
"1.5": "q.run_molang('cobblemon:stepsound_claw_large');"
}
},
"animation.corviknight.ground_run": {
@@ -4477,10 +4473,6 @@
"locator_seat_2": {
"rotation": [25, 0, 0]
}
},
"timeline": {
"0.3333": "q.run_molang('cobblemon:stepsound_claw_large');",
"0.8333": "q.run_molang('cobblemon:stepsound_claw_large');"
}
},
"animation.corviknight.air_idle": {
@@ -566,12 +566,6 @@
"1.5": [0, 0.2, 0]
}
}
},
"timeline": {
"0.5417": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"0.7083": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"1.2917": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"1.4583": "q.run_molang('cobblemon:stepsound_hoof_medium');"
}
},
"animation.wyrdeer.sleep": {
@@ -786,27 +780,15 @@
"eyelid_right": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"0.5": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
}
"0.25": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"0.5": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"0.25": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"0.5": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
}
"0.25": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"0.5": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"ear_right": {
@@ -1204,36 +1186,18 @@
"position": {
"0.0": [0, 0, 0],
"1.5833": [-0.1, 0, -0.1],
"1.6667": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
},
"3.0": {
"pre": [0, 0, 0],
"post": [-0.1, 0, -0.1]
},
"3.125": {
"pre": [-0.1, 0, -0.1],
"post": [0, 0, 0]
}
"1.6667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
"3.0": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
"3.125": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"eyelid_left": {
"position": {
"0.0": [0, 0, 0],
"1.5833": [0.1, 0, -0.1],
"1.6667": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
},
"3.0": {
"pre": [0, 0, 0],
"post": [0.1, 0, -0.1]
},
"3.125": {
"pre": [0.1, 0, -0.1],
"post": [0, 0, 0]
}
"1.6667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
"3.0": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
"3.125": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
}
},
"tail": {
@@ -2240,16 +2204,6 @@
"1.1667": [0, 0, 0]
}
}
},
"timeline": {
"0.2083": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"0.2917": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"0.375": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"0.4583": "q.run_molang('cobblemon:stepsound_hoof_large');",
"0.7917": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"0.875": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"0.9583": "q.run_molang('cobblemon:stepsound_hoof_medium');",
"1.0417": "q.run_molang('cobblemon:stepsound_hoof_large');"
}
},
"animation.wyrdeer.ride_jump": {
@@ -800,8 +800,6 @@
"block.cobblemon.relic_coin_sack": "Relic Coin Sack",
"item.cobblemon.automaton_armor_trim_smithing_template": "Smithing Template",
"trim_pattern.cobblemon.automaton": "Automaton Armor Trim",
"item.cobblemon.trainer_pack": "Trainer Pack",
"item.cobblemon.trainer_bag": "Trainer Bag",
"cobblemon.tooltip.see_more_info": "Hold shift to see info",
"cobblemon.item_class.fishing_bait": "Fishing Bait",
"cobblemon.item_class.cooking_pot_recipe_absorbs": "Absorbs",
@@ -1200,14 +1198,7 @@
"cobblemon.ui.edit.habitat.validation.phases_list": "Phases must use a valid format for integer ranges, e.g. 1-3 or 1, 3-5, 6.",
"cobblemon.ui.edit.habitat.validation.min_light": "Min Light must be between 0 and 15.",
"cobblemon.ui.edit.habitat.validation.max_light": "Max Light must be between 0 and 15.",
"cobblemon.container.bag": "Trainer Bag",
"cobblemon.bag_category.poke_balls": "Poké Balls",
"cobblemon.bag_category.consumables": "Consumables",
"cobblemon.bag_category.berries": "Berries",
"cobblemon.bag_category.held_evo": "Held and Evolution Items",
"cobblemon.bag_category.tms": "Technical Machines",
"cobblemon.bag_category.currency": "Currency",
"cobblemon.bag_categories.all_items": "Bag",
"cobblemon.ui.pokenav.title": "PokéNav",
"cobblemon.ui.pokenav.narrator.backbutton": "PokéNav button pressed",
@@ -3680,6 +3671,12 @@
"tag.item.cobblemon.terrain_plants": "Terrain Plants",
"tag.item.cobblemon.tall_flowers": "Tall Flowers",
"tag.item.cobblemon.small_flowers": "Small Flowers",
"tag.item.cobblemon.drops.coral": "Any Coral",
"tag.item.cobblemon.drops.dead_coral": "Any Dead Coral",
"tag.item.cobblemon.drops.dyes": "Any Dye",
"tag.item.cobblemon.drops.ink_sacs": "Any Ink Sac",
"tag.item.cobblemon.drops.flowers": "Any Flower",
"tag.item.cobblemon.drops.apricorn_sprouts": "Any Apricorn Sprout",
"tag.worldgen.biome.cobblemon.evolution.regional.bergmite_hisuibiome": "Hisuian",
"tag.worldgen.biome.cobblemon.evolution.regional.bergmite_kalosbiome": "Kalosian",
@@ -1,131 +0,0 @@
{
"format_version": "1.9.0",
"credit": "Made with Blockbench",
"texture_size": [64, 64],
"textures": {
"particle": "cobblemon:item/bag/bag_penny",
"texture": "cobblemon:item/bag/bag_penny"
},
"elements": [
{
"name": "straps",
"from": [3.65, 11.65, 5.65],
"to": [12.35, 24.35, 10.35],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [1, 1, 3, 4], "texture": "#texture"},
"east": {"uv": [0, 1, 1, 4], "texture": "#texture"},
"south": {"uv": [4, 1, 6, 4], "texture": "#texture"},
"west": {"uv": [3, 1, 4, 4], "texture": "#texture"},
"up": {"uv": [3, 1, 1, 0], "texture": "#texture"},
"down": {"uv": [5, 0, 3, 1], "texture": "#texture"}
}
},
{
"name": "bag",
"from": [4.51, 19.01, 10.01],
"to": [11.49, 21.99, 12.99],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 19.5, 11.5]},
"faces": {
"north": {"uv": [6.75, 2.5, 8.5, 3.25], "texture": "#texture"},
"east": {"uv": [6, 2.5, 6.75, 3.25], "texture": "#texture"},
"south": {"uv": [9.25, 2.5, 11, 3.25], "texture": "#texture"},
"west": {"uv": [8.5, 2.5, 9.25, 3.25], "texture": "#texture"},
"up": {"uv": [8.5, 2.5, 6.75, 1.75], "texture": "#texture"},
"down": {"uv": [10.25, 1.75, 8.5, 2.5], "texture": "#texture"}
}
},
{
"name": "bag",
"from": [1.99, 21.99, 12.49],
"to": [14.01, 26.01, 12.51],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 22, 12.5]},
"faces": {
"north": {"uv": [7.5, 3.75, 10.5, 4.75], "texture": "#texture"},
"east": {"uv": [7.5, 3.75, 7.5, 4.75], "texture": "#texture"},
"south": {"uv": [10.5, 3.75, 13.5, 4.75], "texture": "#texture"},
"west": {"uv": [10.5, 3.75, 10.5, 4.75], "texture": "#texture"},
"up": {"uv": [10.5, 3.75, 7.5, 3.75], "texture": "#texture"},
"down": {"uv": [13.5, 3.75, 10.5, 3.75], "texture": "#texture"}
}
},
{
"name": "bag",
"from": [4.51, 12.51, 10.01],
"to": [11.49, 16.49, 12.99],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 14, 11.5]},
"faces": {
"north": {"uv": [6.75, 0.75, 8.5, 1.75], "texture": "#texture"},
"east": {"uv": [6, 0.75, 6.75, 1.75], "texture": "#texture"},
"south": {"uv": [9.25, 0.75, 11, 1.75], "texture": "#texture"},
"west": {"uv": [8.5, 0.75, 9.25, 1.75], "texture": "#texture"},
"up": {"uv": [8.5, 0.75, 6.75, 0], "texture": "#texture"},
"down": {"uv": [10.25, 0, 8.5, 0.75], "texture": "#texture"}
}
},
{
"name": "bag",
"from": [4.99, 11.49, 11.99],
"to": [11.01, 12.51, 12.01],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 12, 11]},
"faces": {
"north": {"uv": [6, 5, 7.5, 5.25], "texture": "#texture"},
"east": {"uv": [6, 5, 6, 5.25], "texture": "#texture"},
"south": {"uv": [7.5, 5, 9, 5.25], "texture": "#texture"},
"west": {"uv": [7.5, 5, 7.5, 5.25], "texture": "#texture"},
"up": {"uv": [7.5, 5, 6, 5], "texture": "#texture"},
"down": {"uv": [9, 5, 7.5, 5], "texture": "#texture"}
}
},
{
"name": "bag",
"from": [5.99, 8.49, 10.99],
"to": [10.01, 12.51, 11.01],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 10, 10.5]},
"faces": {
"north": {"uv": [6, 5.5, 7, 6.5], "texture": "#texture"},
"east": {"uv": [6, 5.5, 6, 6.5], "texture": "#texture"},
"south": {"uv": [7, 5.5, 8, 6.5], "texture": "#texture"},
"west": {"uv": [7, 5.5, 7, 6.5], "texture": "#texture"},
"up": {"uv": [7, 5.5, 6, 5.5], "texture": "#texture"},
"down": {"uv": [8, 5.5, 7, 5.5], "texture": "#texture"}
}
},
{
"name": "bag",
"from": [4.01, 16.01, 9.51],
"to": [11.99, 18.99, 13.49],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 16.5, 11]},
"faces": {
"north": {"uv": [1, 5, 3, 5.75], "texture": "#texture"},
"east": {"uv": [0, 5, 1, 5.75], "texture": "#texture"},
"south": {"uv": [4, 5, 6, 5.75], "texture": "#texture"},
"west": {"uv": [3, 5, 4, 5.75], "texture": "#texture"},
"up": {"uv": [3, 5, 1, 4], "texture": "#texture"},
"down": {"uv": [5, 4, 3, 5], "texture": "#texture"}
}
},
{
"name": "bag",
"from": [3.8, 15.8, 9.3],
"to": [12.2, 19.2, 13.7],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 16.5, 11]},
"faces": {
"north": {"uv": [1, 6.75, 3, 7.5], "texture": "#texture"},
"east": {"uv": [0, 6.75, 1, 7.5], "texture": "#texture"},
"south": {"uv": [4, 6.75, 6, 7.5], "texture": "#texture"},
"west": {"uv": [3, 6.75, 4, 7.5], "texture": "#texture"},
"up": {"uv": [3, 6.75, 1, 5.75], "texture": "#texture"},
"down": {"uv": [5, 5.75, 3, 6.75], "texture": "#texture"}
}
}
],
"groups": [
{
"name": "bag",
"origin": [0, 0, 0],
"color": 0,
"children": [0, 1, 2, 3, 4, 5, 6, 7]
}
]
}
@@ -1,63 +0,0 @@
{
"format_version": "1.9.0",
"credit": "Made with Blockbench",
"texture_size": [32, 32],
"textures": {
"0": "cobblemon:item/bag/trainer_bag",
"particle": "cobblemon:item/bag/trainer_bag"
},
"elements": [
{
"name": "straps",
"from": [3.65, 11.65, 5.65],
"to": [12.35, 24.35, 10.35],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [2, 2, 6, 8], "texture": "#0"},
"east": {"uv": [0, 2, 2, 8], "texture": "#0"},
"south": {"uv": [8, 2, 12, 8], "texture": "#0"},
"west": {"uv": [6, 2, 8, 8], "texture": "#0"},
"up": {"uv": [6, 2, 2, 0], "texture": "#0"},
"down": {"uv": [10, 0, 6, 2], "texture": "#0"}
}
},
{
"name": "straps inverted",
"from": [12.35, 24.35, 10.35],
"to": [3.65, 11.65, 5.65],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [8, 8, 12, 2], "texture": "#0"},
"east": {"uv": [6, 8, 8, 2], "texture": "#0"},
"south": {"uv": [2, 8, 6, 2], "texture": "#0"},
"west": {"uv": [0, 8, 2, 2], "texture": "#0"},
"up": {"uv": [6, 0, 10, 2], "texture": "#0"},
"down": {"uv": [2, 2, 6, 0], "texture": "#0"}
}
},
{
"name": "bag",
"from": [4, 14, 10],
"to": [12, 20, 13],
"rotation": {"angle": 22.5, "axis": "z", "origin": [8, 17, 11.5]},
"faces": {
"north": {"uv": [1.5, 9.5, 5.5, 12.5], "texture": "#0"},
"east": {"uv": [0, 9.5, 1.5, 12.5], "texture": "#0"},
"south": {"uv": [7, 9.5, 11, 12.5], "texture": "#0"},
"west": {"uv": [5.5, 9.5, 7, 12.5], "texture": "#0"},
"up": {"uv": [5.5, 9.5, 1.5, 8], "texture": "#0"},
"down": {"uv": [9.5, 8, 5.5, 9.5], "texture": "#0"}
}
}
],
"gui_light": "front",
"groups": [
{
"name": "bag",
"origin": [8, 0, 8],
"scope": 0,
"color": 0,
"children": [0, 1, 2]
}
]
}
@@ -1,101 +0,0 @@
{
"format_version": "1.9.0",
"credit": "Made with Blockbench",
"texture_size": [64, 32],
"textures": {
"0": "cobblemon:item/bag/trainer_pack",
"particle": "cobblemon:item/bag/trainer_pack"
},
"elements": [
{
"name": "straps",
"from": [3.65, 11.65, 5.65],
"to": [12.35, 24.35, 10.35],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [1, 2, 3, 8], "texture": "#0"},
"east": {"uv": [0, 2, 1, 8], "texture": "#0"},
"south": {"uv": [4, 2, 6, 8], "texture": "#0"},
"west": {"uv": [3, 2, 4, 8], "texture": "#0"},
"up": {"uv": [3, 2, 1, 0], "texture": "#0"},
"down": {"uv": [5, 0, 3, 2], "texture": "#0"}
}
},
{
"name": "straps inverted",
"from": [12.35, 24.35, 10.35],
"to": [3.65, 11.65, 5.65],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 8]},
"faces": {
"north": {"uv": [4, 8, 6, 2], "texture": "#0"},
"east": {"uv": [3, 8, 4, 2], "texture": "#0"},
"south": {"uv": [1, 8, 3, 2], "texture": "#0"},
"west": {"uv": [0, 8, 1, 2], "texture": "#0"},
"up": {"uv": [3, 0, 5, 2], "texture": "#0"},
"down": {"uv": [1, 2, 3, 0], "texture": "#0"}
}
},
{
"name": "bag",
"from": [6, 21.5, 11.5],
"to": [10, 23.5, 11.5],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 24, 11.5]},
"faces": {
"north": {"uv": [6.25, 5, 7.25, 6], "texture": "#0"},
"south": {"uv": [7.25, 5, 8.25, 6], "texture": "#0"}
}
},
{
"name": "bag",
"from": [4.01, 16.5, 10],
"to": [11.99, 21.5, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 15.5, 11.5]},
"faces": {
"north": {"uv": [7.25, 2, 9.25, 4.5], "texture": "#0"},
"east": {"uv": [6.25, 2, 7.25, 4.5], "texture": "#0"},
"south": {"uv": [10.25, 2, 12.25, 4.5], "texture": "#0"},
"west": {"uv": [9.25, 2, 10.25, 4.5], "texture": "#0"},
"up": {"uv": [9.25, 2, 7.25, 0], "texture": "#0"},
"down": {"uv": [11.25, 0, 9.25, 2], "texture": "#0"}
}
},
{
"name": "bag",
"from": [3.5, 12.5, 10],
"to": [12.5, 16.5, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 15.5, 11.5]},
"faces": {
"north": {"uv": [1, 14, 3.25, 16], "texture": "#0"},
"east": {"uv": [0, 14, 1, 16], "texture": "#0"},
"south": {"uv": [4.25, 14, 6.5, 16], "texture": "#0"},
"west": {"uv": [3.25, 14, 4.25, 16], "texture": "#0"},
"up": {"uv": [3.25, 14, 1, 12], "texture": "#0"},
"down": {"uv": [5.5, 12, 3.25, 14], "texture": "#0"}
}
},
{
"name": "bag",
"from": [4.5, 12.5, 14],
"to": [11.5, 16.5, 15],
"rotation": {"angle": 0, "axis": "y", "origin": [6.5, 16.5, 15.5]},
"faces": {
"north": {"uv": [0.25, 10, 2, 12], "texture": "#0"},
"east": {"uv": [0, 10, 0.25, 12], "texture": "#0"},
"south": {"uv": [2.25, 10, 4, 12], "texture": "#0"},
"west": {"uv": [2, 10, 2.25, 12], "texture": "#0"},
"up": {"uv": [2, 10, 0.25, 9.5], "texture": "#0"},
"down": {"uv": [3.75, 9.5, 2, 10], "texture": "#0"}
}
}
],
"gui_light": "front",
"groups": [
{
"name": "bag",
"origin": [8, 0, 8],
"scope": 0,
"color": 0,
"children": [0, 1, 2, 3, 4, 5]
}
]
}
@@ -1,47 +0,0 @@
{
"parent": "cobblemon:item/bag/trainer_bag",
"gui_light": "front",
"display": {
"thirdperson_righthand": {
"rotation": [75, -155, 0],
"translation": [2.25, -4, -11],
"scale": [0.75, 0.75, 0.75]
},
"thirdperson_lefthand": {
"rotation": [75, -155, 0],
"translation": [2.25, -4, -11],
"scale": [0.75, 0.75, 0.75]
},
"firstperson_righthand": {
"rotation": [0, -100, 0],
"translation": [5, -7, 0],
"scale": [0.8, 0.8, 0.8]
},
"firstperson_lefthand": {
"rotation": [0, -100, 0],
"translation": [5, -7, 0],
"scale": [0.8, 0.8, 0.8]
},
"ground": {
"translation": [0, -3, -1.75],
"scale": [0.5, 0.5, 0.5]
},
"gui": {
"rotation": [30, -22.5, 0],
"translation": [0.75, -7, 0],
"scale": [0.875, 0.875, 0.875]
},
"head": {
"translation": [0, -32.25, 0],
"scale": [1.6, 1.6, 1.6]
},
"fixed": {
"rotation": [0, -180, 0],
"translation": [0, -9.25, 3.5]
},
"on_shelf": {
"translation": [0, 0, -7.5],
"scale": [1.75, 1.75, 1.75]
}
}
}
@@ -1,47 +0,0 @@
{
"parent": "cobblemon:item/bag/trainer_pack",
"gui_light": "front",
"display": {
"thirdperson_righthand": {
"rotation": [75, -155, 0],
"translation": [2.25, -4, -11],
"scale": [0.75, 0.75, 0.75]
},
"thirdperson_lefthand": {
"rotation": [75, -155, 0],
"translation": [2.25, -4, -11],
"scale": [0.75, 0.75, 0.75]
},
"firstperson_righthand": {
"rotation": [0, -100, 0],
"translation": [5, -7, 0],
"scale": [0.8, 0.8, 0.8]
},
"firstperson_lefthand": {
"rotation": [0, -100, 0],
"translation": [5, -7, 0],
"scale": [0.8, 0.8, 0.8]
},
"ground": {
"translation": [0, -3, -1.75],
"scale": [0.5, 0.5, 0.5]
},
"gui": {
"rotation": [30, -22.5, 0],
"translation": [0.75, -7, 0],
"scale": [0.875, 0.875, 0.875]
},
"head": {
"translation": [0, -32.25, 0],
"scale": [1.6, 1.6, 1.6]
},
"fixed": {
"rotation": [0, -180, 0],
"translation": [0, -9.25, 3.5]
},
"on_shelf": {
"translation": [0, 0, -7.5],
"scale": [1.75, 1.75, 1.75]
}
}
}
@@ -261,24 +261,6 @@
"fishing.bait_detach": {
"sounds": [ { "name": "cobblemon:fishing/fishing_rod_remove_bait", "volume": 0.8 } ]
},
"item.bag.open": {
"sounds": [ { "name": "cobblemon:item/bag/bag_open", "volume": 0.5 } ]
},
"item.bag.close": {
"sounds": [ { "name": "cobblemon:item/bag/bag_close", "volume": 0.5 } ]
},
"item.bag.click": {
"sounds": [ { "name": "cobblemon:item/bag/bag_click", "volume": 0.3 } ]
},
"item.bag.item_in": {
"sounds": [ { "name": "cobblemon:item/bag/bag_item_in", "volume": 0.3 } ]
},
"item.bag.item_out": {
"sounds": [ { "name": "cobblemon:item/bag/bag_item_out", "volume": 0.3 } ]
},
"item.bag.equip": {
"sounds": [ { "name": "cobblemon:item/bag/bag_equip", "volume": 0.4 } ]
},
"block.healing_machine.active": {
"sounds": [ { "name": "cobblemon:block/healing_machine/healing_machine_active", "volume": 0.7 } ]
},
@@ -2049,850 +2031,6 @@
{ "name": "cobblemon:animation/wings/steel_wing_flap_medium_8", "volume": 0.25 }
]
},
"stepsound.dirt.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/dirt/standard/large/stepsound_dirt_standard_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/dirt/standard/large/stepsound_dirt_standard_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/dirt/standard/large/stepsound_dirt_standard_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/dirt/standard/large/stepsound_dirt_standard_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/dirt/standard/large/stepsound_dirt_standard_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/dirt/standard/large/stepsound_dirt_standard_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/dirt/standard/large/stepsound_dirt_standard_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/dirt/standard/large/stepsound_dirt_standard_large_8", "volume": 0.2 }
]
},
"stepsound.dirt.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/dirt/standard/medium/stepsound_dirt_standard_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/dirt/standard/medium/stepsound_dirt_standard_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/dirt/standard/medium/stepsound_dirt_standard_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/dirt/standard/medium/stepsound_dirt_standard_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/dirt/standard/medium/stepsound_dirt_standard_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/dirt/standard/medium/stepsound_dirt_standard_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/dirt/standard/medium/stepsound_dirt_standard_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/dirt/standard/medium/stepsound_dirt_standard_medium_8", "volume": 0.1 }
]
},
"stepsound.grass.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/grass/standard/large/stepsound_grass_standard_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/grass/standard/large/stepsound_grass_standard_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/grass/standard/large/stepsound_grass_standard_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/grass/standard/large/stepsound_grass_standard_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/grass/standard/large/stepsound_grass_standard_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/grass/standard/large/stepsound_grass_standard_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/grass/standard/large/stepsound_grass_standard_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/grass/standard/large/stepsound_grass_standard_large_8", "volume": 0.2 }
]
},
"stepsound.grass.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/grass/standard/medium/stepsound_grass_standard_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/grass/standard/medium/stepsound_grass_standard_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/grass/standard/medium/stepsound_grass_standard_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/grass/standard/medium/stepsound_grass_standard_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/grass/standard/medium/stepsound_grass_standard_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/grass/standard/medium/stepsound_grass_standard_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/grass/standard/medium/stepsound_grass_standard_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/grass/standard/medium/stepsound_grass_standard_medium_8", "volume": 0.1 }
]
},
"stepsound.stone.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/stone/standard/large/stepsound_stone_standard_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/stone/standard/large/stepsound_stone_standard_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/stone/standard/large/stepsound_stone_standard_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/stone/standard/large/stepsound_stone_standard_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/stone/standard/large/stepsound_stone_standard_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/stone/standard/large/stepsound_stone_standard_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/stone/standard/large/stepsound_stone_standard_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/stone/standard/large/stepsound_stone_standard_large_8", "volume": 0.2 }
]
},
"stepsound.stone.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/stone/standard/medium/stepsound_stone_standard_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/stone/standard/medium/stepsound_stone_standard_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/stone/standard/medium/stepsound_stone_standard_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/stone/standard/medium/stepsound_stone_standard_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/stone/standard/medium/stepsound_stone_standard_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/stone/standard/medium/stepsound_stone_standard_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/stone/standard/medium/stepsound_stone_standard_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/stone/standard/medium/stepsound_stone_standard_medium_8", "volume": 0.1 }
]
},
"stepsound.sand.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/sand/standard/large/stepsound_sand_standard_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/standard/large/stepsound_sand_standard_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/standard/large/stepsound_sand_standard_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/standard/large/stepsound_sand_standard_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/standard/large/stepsound_sand_standard_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/standard/large/stepsound_sand_standard_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/standard/large/stepsound_sand_standard_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/standard/large/stepsound_sand_standard_large_8", "volume": 0.2 }
]
},
"stepsound.sand.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/sand/standard/medium/stepsound_sand_standard_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/standard/medium/stepsound_sand_standard_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/standard/medium/stepsound_sand_standard_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/standard/medium/stepsound_sand_standard_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/standard/medium/stepsound_sand_standard_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/standard/medium/stepsound_sand_standard_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/standard/medium/stepsound_sand_standard_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/standard/medium/stepsound_sand_standard_medium_8", "volume": 0.1 }
]
},
"stepsound.snow.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/snow/standard/large/stepsound_snow_standard_large_1", "volume": 0.18 },
{ "name": "cobblemon:stepsound/snow/standard/large/stepsound_snow_standard_large_2", "volume": 0.18 },
{ "name": "cobblemon:stepsound/snow/standard/large/stepsound_snow_standard_large_3", "volume": 0.18 },
{ "name": "cobblemon:stepsound/snow/standard/large/stepsound_snow_standard_large_4", "volume": 0.18 },
{ "name": "cobblemon:stepsound/snow/standard/large/stepsound_snow_standard_large_5", "volume": 0.18 },
{ "name": "cobblemon:stepsound/snow/standard/large/stepsound_snow_standard_large_6", "volume": 0.18 },
{ "name": "cobblemon:stepsound/snow/standard/large/stepsound_snow_standard_large_7", "volume": 0.18 },
{ "name": "cobblemon:stepsound/snow/standard/large/stepsound_snow_standard_large_8", "volume": 0.18 }
]
},
"stepsound.snow.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/snow/standard/medium/stepsound_snow_standard_medium_1", "volume": 0.08 },
{ "name": "cobblemon:stepsound/snow/standard/medium/stepsound_snow_standard_medium_2", "volume": 0.08 },
{ "name": "cobblemon:stepsound/snow/standard/medium/stepsound_snow_standard_medium_3", "volume": 0.08 },
{ "name": "cobblemon:stepsound/snow/standard/medium/stepsound_snow_standard_medium_4", "volume": 0.08 },
{ "name": "cobblemon:stepsound/snow/standard/medium/stepsound_snow_standard_medium_5", "volume": 0.08 },
{ "name": "cobblemon:stepsound/snow/standard/medium/stepsound_snow_standard_medium_6", "volume": 0.08 },
{ "name": "cobblemon:stepsound/snow/standard/medium/stepsound_snow_standard_medium_7", "volume": 0.08 },
{ "name": "cobblemon:stepsound/snow/standard/medium/stepsound_snow_standard_medium_8", "volume": 0.08 }
]
},
"stepsound.wood.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/wood/standard/large/stepsound_wood_standard_large_1", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/standard/large/stepsound_wood_standard_large_2", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/standard/large/stepsound_wood_standard_large_3", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/standard/large/stepsound_wood_standard_large_4", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/standard/large/stepsound_wood_standard_large_5", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/standard/large/stepsound_wood_standard_large_6", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/standard/large/stepsound_wood_standard_large_7", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/standard/large/stepsound_wood_standard_large_8", "volume": 0.25 }
]
},
"stepsound.wood.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/wood/standard/medium/stepsound_wood_standard_medium_1", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/standard/medium/stepsound_wood_standard_medium_2", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/standard/medium/stepsound_wood_standard_medium_3", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/standard/medium/stepsound_wood_standard_medium_4", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/standard/medium/stepsound_wood_standard_medium_5", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/standard/medium/stepsound_wood_standard_medium_6", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/standard/medium/stepsound_wood_standard_medium_7", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/standard/medium/stepsound_wood_standard_medium_8", "volume": 0.15 }
]
},
"stepsound.mud.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/mud/standard/large/stepsound_mud_standard_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/standard/large/stepsound_mud_standard_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/standard/large/stepsound_mud_standard_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/standard/large/stepsound_mud_standard_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/standard/large/stepsound_mud_standard_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/standard/large/stepsound_mud_standard_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/standard/large/stepsound_mud_standard_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/standard/large/stepsound_mud_standard_large_8", "volume": 0.22 }
]
},
"stepsound.mud.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/mud/standard/medium/stepsound_mud_standard_medium_1", "volume": 0.14 },
{ "name": "cobblemon:stepsound/mud/standard/medium/stepsound_mud_standard_medium_2", "volume": 0.14 },
{ "name": "cobblemon:stepsound/mud/standard/medium/stepsound_mud_standard_medium_3", "volume": 0.14 },
{ "name": "cobblemon:stepsound/mud/standard/medium/stepsound_mud_standard_medium_4", "volume": 0.14 },
{ "name": "cobblemon:stepsound/mud/standard/medium/stepsound_mud_standard_medium_5", "volume": 0.14 },
{ "name": "cobblemon:stepsound/mud/standard/medium/stepsound_mud_standard_medium_6", "volume": 0.14 },
{ "name": "cobblemon:stepsound/mud/standard/medium/stepsound_mud_standard_medium_7", "volume": 0.14 },
{ "name": "cobblemon:stepsound/mud/standard/medium/stepsound_mud_standard_medium_8", "volume": 0.14 }
]
},
"stepsound.glass.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/glass/standard/large/stepsound_glass_standard_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/standard/large/stepsound_glass_standard_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/standard/large/stepsound_glass_standard_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/standard/large/stepsound_glass_standard_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/standard/large/stepsound_glass_standard_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/standard/large/stepsound_glass_standard_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/standard/large/stepsound_glass_standard_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/standard/large/stepsound_glass_standard_large_8", "volume": 0.2 }
]
},
"stepsound.glass.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/glass/standard/medium/stepsound_glass_standard_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/standard/medium/stepsound_glass_standard_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/standard/medium/stepsound_glass_standard_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/standard/medium/stepsound_glass_standard_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/standard/medium/stepsound_glass_standard_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/standard/medium/stepsound_glass_standard_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/standard/medium/stepsound_glass_standard_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/standard/medium/stepsound_glass_standard_medium_8", "volume": 0.1 }
]
},
"stepsound.metal.standard.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/metal/standard/large/stepsound_metal_standard_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/standard/large/stepsound_metal_standard_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/standard/large/stepsound_metal_standard_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/standard/large/stepsound_metal_standard_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/standard/large/stepsound_metal_standard_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/standard/large/stepsound_metal_standard_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/standard/large/stepsound_metal_standard_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/standard/large/stepsound_metal_standard_large_8", "volume": 0.2 }
]
},
"stepsound.metal.standard.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/metal/standard/medium/stepsound_metal_standard_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/standard/medium/stepsound_metal_standard_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/standard/medium/stepsound_metal_standard_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/standard/medium/stepsound_metal_standard_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/standard/medium/stepsound_metal_standard_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/standard/medium/stepsound_metal_standard_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/standard/medium/stepsound_metal_standard_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/standard/medium/stepsound_metal_standard_medium_8", "volume": 0.1 }
]
},
"stepsound.dirt.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/dirt/hoof/large/stepsound_dirt_hoof_large_1", "volume": 0.25 },
{ "name": "cobblemon:stepsound/dirt/hoof/large/stepsound_dirt_hoof_large_2", "volume": 0.25 },
{ "name": "cobblemon:stepsound/dirt/hoof/large/stepsound_dirt_hoof_large_3", "volume": 0.25 },
{ "name": "cobblemon:stepsound/dirt/hoof/large/stepsound_dirt_hoof_large_4", "volume": 0.25 },
{ "name": "cobblemon:stepsound/dirt/hoof/large/stepsound_dirt_hoof_large_5", "volume": 0.25 },
{ "name": "cobblemon:stepsound/dirt/hoof/large/stepsound_dirt_hoof_large_6", "volume": 0.25 },
{ "name": "cobblemon:stepsound/dirt/hoof/large/stepsound_dirt_hoof_large_7", "volume": 0.25 },
{ "name": "cobblemon:stepsound/dirt/hoof/large/stepsound_dirt_hoof_large_8", "volume": 0.25 }
]
},
"stepsound.dirt.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/dirt/hoof/medium/stepsound_dirt_hoof_medium_1", "volume": 0.15 },
{ "name": "cobblemon:stepsound/dirt/hoof/medium/stepsound_dirt_hoof_medium_2", "volume": 0.15 },
{ "name": "cobblemon:stepsound/dirt/hoof/medium/stepsound_dirt_hoof_medium_3", "volume": 0.15 },
{ "name": "cobblemon:stepsound/dirt/hoof/medium/stepsound_dirt_hoof_medium_4", "volume": 0.15 },
{ "name": "cobblemon:stepsound/dirt/hoof/medium/stepsound_dirt_hoof_medium_5", "volume": 0.15 },
{ "name": "cobblemon:stepsound/dirt/hoof/medium/stepsound_dirt_hoof_medium_6", "volume": 0.15 },
{ "name": "cobblemon:stepsound/dirt/hoof/medium/stepsound_dirt_hoof_medium_7", "volume": 0.15 },
{ "name": "cobblemon:stepsound/dirt/hoof/medium/stepsound_dirt_hoof_medium_8", "volume": 0.15 }
]
},
"stepsound.grass.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/grass/hoof/large/stepsound_grass_hoof_large_1", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/hoof/large/stepsound_grass_hoof_large_2", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/hoof/large/stepsound_grass_hoof_large_3", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/hoof/large/stepsound_grass_hoof_large_4", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/hoof/large/stepsound_grass_hoof_large_5", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/hoof/large/stepsound_grass_hoof_large_6", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/hoof/large/stepsound_grass_hoof_large_7", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/hoof/large/stepsound_grass_hoof_large_8", "volume": 0.25 }
]
},
"stepsound.grass.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/grass/hoof/medium/stepsound_grass_hoof_medium_1", "volume": 0.15 },
{ "name": "cobblemon:stepsound/grass/hoof/medium/stepsound_grass_hoof_medium_2", "volume": 0.15 },
{ "name": "cobblemon:stepsound/grass/hoof/medium/stepsound_grass_hoof_medium_3", "volume": 0.15 },
{ "name": "cobblemon:stepsound/grass/hoof/medium/stepsound_grass_hoof_medium_4", "volume": 0.15 },
{ "name": "cobblemon:stepsound/grass/hoof/medium/stepsound_grass_hoof_medium_5", "volume": 0.15 },
{ "name": "cobblemon:stepsound/grass/hoof/medium/stepsound_grass_hoof_medium_6", "volume": 0.15 },
{ "name": "cobblemon:stepsound/grass/hoof/medium/stepsound_grass_hoof_medium_7", "volume": 0.15 },
{ "name": "cobblemon:stepsound/grass/hoof/medium/stepsound_grass_hoof_medium_8", "volume": 0.15 }
]
},
"stepsound.stone.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/stone/hoof/large/stepsound_stone_hoof_large_1", "volume": 0.25 },
{ "name": "cobblemon:stepsound/stone/hoof/large/stepsound_stone_hoof_large_2", "volume": 0.25 },
{ "name": "cobblemon:stepsound/stone/hoof/large/stepsound_stone_hoof_large_3", "volume": 0.25 },
{ "name": "cobblemon:stepsound/stone/hoof/large/stepsound_stone_hoof_large_4", "volume": 0.25 },
{ "name": "cobblemon:stepsound/stone/hoof/large/stepsound_stone_hoof_large_5", "volume": 0.25 },
{ "name": "cobblemon:stepsound/stone/hoof/large/stepsound_stone_hoof_large_6", "volume": 0.25 },
{ "name": "cobblemon:stepsound/stone/hoof/large/stepsound_stone_hoof_large_7", "volume": 0.25 },
{ "name": "cobblemon:stepsound/stone/hoof/large/stepsound_stone_hoof_large_8", "volume": 0.25 }
]
},
"stepsound.stone.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/stone/hoof/medium/stepsound_stone_hoof_medium_1", "volume": 0.15 },
{ "name": "cobblemon:stepsound/stone/hoof/medium/stepsound_stone_hoof_medium_2", "volume": 0.15 },
{ "name": "cobblemon:stepsound/stone/hoof/medium/stepsound_stone_hoof_medium_3", "volume": 0.15 },
{ "name": "cobblemon:stepsound/stone/hoof/medium/stepsound_stone_hoof_medium_4", "volume": 0.15 },
{ "name": "cobblemon:stepsound/stone/hoof/medium/stepsound_stone_hoof_medium_5", "volume": 0.15 },
{ "name": "cobblemon:stepsound/stone/hoof/medium/stepsound_stone_hoof_medium_6", "volume": 0.15 },
{ "name": "cobblemon:stepsound/stone/hoof/medium/stepsound_stone_hoof_medium_7", "volume": 0.15 },
{ "name": "cobblemon:stepsound/stone/hoof/medium/stepsound_stone_hoof_medium_8", "volume": 0.15 }
]
},
"stepsound.sand.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/sand/hoof/large/stepsound_sand_hoof_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/hoof/large/stepsound_sand_hoof_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/hoof/large/stepsound_sand_hoof_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/hoof/large/stepsound_sand_hoof_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/hoof/large/stepsound_sand_hoof_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/hoof/large/stepsound_sand_hoof_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/hoof/large/stepsound_sand_hoof_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/sand/hoof/large/stepsound_sand_hoof_large_8", "volume": 0.2 }
]
},
"stepsound.sand.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/sand/hoof/medium/stepsound_sand_hoof_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/hoof/medium/stepsound_sand_hoof_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/hoof/medium/stepsound_sand_hoof_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/hoof/medium/stepsound_sand_hoof_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/hoof/medium/stepsound_sand_hoof_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/hoof/medium/stepsound_sand_hoof_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/hoof/medium/stepsound_sand_hoof_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/sand/hoof/medium/stepsound_sand_hoof_medium_8", "volume": 0.1 }
]
},
"stepsound.snow.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/snow/hoof/large/stepsound_snow_hoof_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/hoof/large/stepsound_snow_hoof_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/hoof/large/stepsound_snow_hoof_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/hoof/large/stepsound_snow_hoof_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/hoof/large/stepsound_snow_hoof_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/hoof/large/stepsound_snow_hoof_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/hoof/large/stepsound_snow_hoof_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/hoof/large/stepsound_snow_hoof_large_8", "volume": 0.22 }
]
},
"stepsound.snow.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/snow/hoof/medium/stepsound_snow_hoof_medium_1", "volume": 0.12 },
{ "name": "cobblemon:stepsound/snow/hoof/medium/stepsound_snow_hoof_medium_2", "volume": 0.12 },
{ "name": "cobblemon:stepsound/snow/hoof/medium/stepsound_snow_hoof_medium_3", "volume": 0.12 },
{ "name": "cobblemon:stepsound/snow/hoof/medium/stepsound_snow_hoof_medium_4", "volume": 0.12 },
{ "name": "cobblemon:stepsound/snow/hoof/medium/stepsound_snow_hoof_medium_5", "volume": 0.12 },
{ "name": "cobblemon:stepsound/snow/hoof/medium/stepsound_snow_hoof_medium_6", "volume": 0.12 },
{ "name": "cobblemon:stepsound/snow/hoof/medium/stepsound_snow_hoof_medium_7", "volume": 0.12 },
{ "name": "cobblemon:stepsound/snow/hoof/medium/stepsound_snow_hoof_medium_8", "volume": 0.12 }
]
},
"stepsound.wood.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/wood/hoof/large/stepsound_wood_hoof_large_1", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/hoof/large/stepsound_wood_hoof_large_2", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/hoof/large/stepsound_wood_hoof_large_3", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/hoof/large/stepsound_wood_hoof_large_4", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/hoof/large/stepsound_wood_hoof_large_5", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/hoof/large/stepsound_wood_hoof_large_6", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/hoof/large/stepsound_wood_hoof_large_7", "volume": 0.25 },
{ "name": "cobblemon:stepsound/wood/hoof/large/stepsound_wood_hoof_large_8", "volume": 0.25 }
]
},
"stepsound.wood.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/wood/hoof/medium/stepsound_wood_hoof_medium_1", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/hoof/medium/stepsound_wood_hoof_medium_2", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/hoof/medium/stepsound_wood_hoof_medium_3", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/hoof/medium/stepsound_wood_hoof_medium_4", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/hoof/medium/stepsound_wood_hoof_medium_5", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/hoof/medium/stepsound_wood_hoof_medium_6", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/hoof/medium/stepsound_wood_hoof_medium_7", "volume": 0.15 },
{ "name": "cobblemon:stepsound/wood/hoof/medium/stepsound_wood_hoof_medium_8", "volume": 0.15 }
]
},
"stepsound.mud.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/mud/hoof/large/stepsound_mud_hoof_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/mud/hoof/large/stepsound_mud_hoof_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/mud/hoof/large/stepsound_mud_hoof_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/mud/hoof/large/stepsound_mud_hoof_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/mud/hoof/large/stepsound_mud_hoof_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/mud/hoof/large/stepsound_mud_hoof_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/mud/hoof/large/stepsound_mud_hoof_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/mud/hoof/large/stepsound_mud_hoof_large_8", "volume": 0.2 }
]
},
"stepsound.mud.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/mud/hoof/medium/stepsound_mud_hoof_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/mud/hoof/medium/stepsound_mud_hoof_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/mud/hoof/medium/stepsound_mud_hoof_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/mud/hoof/medium/stepsound_mud_hoof_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/mud/hoof/medium/stepsound_mud_hoof_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/mud/hoof/medium/stepsound_mud_hoof_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/mud/hoof/medium/stepsound_mud_hoof_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/mud/hoof/medium/stepsound_mud_hoof_medium_8", "volume": 0.1 }
]
},
"stepsound.glass.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/glass/hoof/large/stepsound_glass_hoof_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/hoof/large/stepsound_glass_hoof_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/hoof/large/stepsound_glass_hoof_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/hoof/large/stepsound_glass_hoof_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/hoof/large/stepsound_glass_hoof_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/hoof/large/stepsound_glass_hoof_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/hoof/large/stepsound_glass_hoof_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/glass/hoof/large/stepsound_glass_hoof_large_8", "volume": 0.2 }
]
},
"stepsound.glass.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/glass/hoof/medium/stepsound_glass_hoof_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/hoof/medium/stepsound_glass_hoof_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/hoof/medium/stepsound_glass_hoof_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/hoof/medium/stepsound_glass_hoof_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/hoof/medium/stepsound_glass_hoof_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/hoof/medium/stepsound_glass_hoof_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/hoof/medium/stepsound_glass_hoof_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/glass/hoof/medium/stepsound_glass_hoof_medium_8", "volume": 0.1 }
]
},
"stepsound.metal.hoof.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/metal/hoof/large/stepsound_metal_hoof_large_1", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/hoof/large/stepsound_metal_hoof_large_2", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/hoof/large/stepsound_metal_hoof_large_3", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/hoof/large/stepsound_metal_hoof_large_4", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/hoof/large/stepsound_metal_hoof_large_5", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/hoof/large/stepsound_metal_hoof_large_6", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/hoof/large/stepsound_metal_hoof_large_7", "volume": 0.2 },
{ "name": "cobblemon:stepsound/metal/hoof/large/stepsound_metal_hoof_large_8", "volume": 0.2 }
]
},
"stepsound.metal.hoof.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/metal/hoof/medium/stepsound_metal_hoof_medium_1", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/hoof/medium/stepsound_metal_hoof_medium_2", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/hoof/medium/stepsound_metal_hoof_medium_3", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/hoof/medium/stepsound_metal_hoof_medium_4", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/hoof/medium/stepsound_metal_hoof_medium_5", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/hoof/medium/stepsound_metal_hoof_medium_6", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/hoof/medium/stepsound_metal_hoof_medium_7", "volume": 0.1 },
{ "name": "cobblemon:stepsound/metal/hoof/medium/stepsound_metal_hoof_medium_8", "volume": 0.1 }
]
},
"stepsound.grass.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "step/grass1", "volume": 0.05 },
{ "name": "step/grass2", "volume": 0.05 },
{ "name": "step/grass3", "volume": 0.05 },
{ "name": "step/grass4", "volume": 0.05 },
{ "name": "step/grass5", "volume": 0.05 },
{ "name": "step/grass6", "volume": 0.05 }
]
},
"stepsound.glass.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "step/stone1", "volume": 0.05 },
{ "name": "step/stone2", "volume": 0.05 },
{ "name": "step/stone3", "volume": 0.05 },
{ "name": "step/stone4", "volume": 0.05 },
{ "name": "step/stone5", "volume": 0.05 },
{ "name": "step/stone6", "volume": 0.05 }
]
},
"stepsound.dirt.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "step/gravel1", "volume": 0.05 },
{ "name": "step/gravel2", "volume": 0.05 },
{ "name": "step/gravel3", "volume": 0.05 },
{ "name": "step/gravel4", "volume": 0.05 }
]
},
"stepsound.mud.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "block/mud/step1", "volume": 0.2 },
{ "name": "block/mud/step2", "volume": 0.2 },
{ "name": "block/mud/step3", "volume": 0.2 },
{ "name": "block/mud/step4", "volume": 0.2 },
{ "name": "block/mud/step5", "volume": 0.2 },
{ "name": "block/mud/step6", "volume": 0.2 }
]
},
"stepsound.stone.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "step/stone1", "volume": 0.08 },
{ "name": "step/stone2", "volume": 0.08 },
{ "name": "step/stone3", "volume": 0.08 },
{ "name": "step/stone4", "volume": 0.08 },
{ "name": "step/stone5", "volume": 0.08 },
{ "name": "step/stone6", "volume": 0.08 }
]
},
"stepsound.wood.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "block/cherry_wood/step1", "volume": 0.2 },
{ "name": "block/cherry_wood/step2", "volume": 0.2 },
{ "name": "block/cherry_wood/step3", "volume": 0.2 },
{ "name": "block/cherry_wood/step4", "volume": 0.2 },
{ "name": "block/cherry_wood/step5", "volume": 0.2 },
{ "name": "block/cherry_wood/step6", "volume": 0.2 }
]
},
"stepsound.metal.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "block/copper/step1", "volume": 0.2 },
{ "name": "block/copper/step2", "volume": 0.2 },
{ "name": "block/copper/step3", "volume": 0.2 },
{ "name": "block/copper/step4", "volume": 0.2 },
{ "name": "block/copper/step5", "volume": 0.2 },
{ "name": "block/copper/step6", "volume": 0.2 }
]
},
"stepsound.sand.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "step/sand1", "volume": 0.08 },
{ "name": "step/sand2", "volume": 0.08 },
{ "name": "step/sand3", "volume": 0.08 },
{ "name": "step/sand4", "volume": 0.08 },
{ "name": "step/sand5", "volume": 0.08 }
]
},
"stepsound.snow.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "step/snow1", "volume": 0.08 },
{ "name": "step/snow2", "volume": 0.08 },
{ "name": "step/snow3", "volume": 0.08 },
{ "name": "step/snow4", "volume": 0.08 }
]
},
"stepsound.amethyst.minecraft": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "block/amethyst/step1", "volume": 0.11 },
{ "name": "block/amethyst/step2", "volume": 0.11 },
{ "name": "block/amethyst/step3", "volume": 0.11 },
{ "name": "block/amethyst/step4", "volume": 0.11 },
{ "name": "block/amethyst/step5", "volume": 0.11 },
{ "name": "block/amethyst/step6", "volume": 0.11 },
{ "name": "block/amethyst/step7", "volume": 0.11 },
{ "name": "block/amethyst/step8", "volume": 0.11 },
{ "name": "block/amethyst/step9", "volume": 0.11 },
{ "name": "block/amethyst/step10", "volume": 0.11 },
{ "name": "block/amethyst/step11", "volume": 0.11 },
{ "name": "block/amethyst/step12", "volume": 0.11 },
{ "name": "block/amethyst/step13", "volume": 0.11 },
{ "name": "block/amethyst/step14", "volume": 0.11 }
]
},
"stepsound.grass.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/grass/claw/large/stepsound_grass_claw_large_1", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/claw/large/stepsound_grass_claw_large_2", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/claw/large/stepsound_grass_claw_large_3", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/claw/large/stepsound_grass_claw_large_4", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/claw/large/stepsound_grass_claw_large_5", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/claw/large/stepsound_grass_claw_large_6", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/claw/large/stepsound_grass_claw_large_7", "volume": 0.25 },
{ "name": "cobblemon:stepsound/grass/claw/large/stepsound_grass_claw_large_8", "volume": 0.25 }
]
},
"stepsound.grass.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/grass/claw/medium/stepsound_grass_claw_medium_1", "volume": 0.14 },
{ "name": "cobblemon:stepsound/grass/claw/medium/stepsound_grass_claw_medium_2", "volume": 0.14 },
{ "name": "cobblemon:stepsound/grass/claw/medium/stepsound_grass_claw_medium_3", "volume": 0.14 },
{ "name": "cobblemon:stepsound/grass/claw/medium/stepsound_grass_claw_medium_4", "volume": 0.14 },
{ "name": "cobblemon:stepsound/grass/claw/medium/stepsound_grass_claw_medium_5", "volume": 0.14 },
{ "name": "cobblemon:stepsound/grass/claw/medium/stepsound_grass_claw_medium_6", "volume": 0.14 },
{ "name": "cobblemon:stepsound/grass/claw/medium/stepsound_grass_claw_medium_7", "volume": 0.14 },
{ "name": "cobblemon:stepsound/grass/claw/medium/stepsound_grass_claw_medium_8", "volume": 0.14 }
]
},
"stepsound.dirt.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/dirt/claw/large/stepsound_dirt_claw_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/dirt/claw/large/stepsound_dirt_claw_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/dirt/claw/large/stepsound_dirt_claw_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/dirt/claw/large/stepsound_dirt_claw_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/dirt/claw/large/stepsound_dirt_claw_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/dirt/claw/large/stepsound_dirt_claw_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/dirt/claw/large/stepsound_dirt_claw_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/dirt/claw/large/stepsound_dirt_claw_large_8", "volume": 0.22 }
]
},
"stepsound.dirt.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/dirt/claw/medium/stepsound_dirt_claw_medium_1", "volume": 0.11 },
{ "name": "cobblemon:stepsound/dirt/claw/medium/stepsound_dirt_claw_medium_2", "volume": 0.11 },
{ "name": "cobblemon:stepsound/dirt/claw/medium/stepsound_dirt_claw_medium_3", "volume": 0.11 },
{ "name": "cobblemon:stepsound/dirt/claw/medium/stepsound_dirt_claw_medium_4", "volume": 0.11 },
{ "name": "cobblemon:stepsound/dirt/claw/medium/stepsound_dirt_claw_medium_5", "volume": 0.11 },
{ "name": "cobblemon:stepsound/dirt/claw/medium/stepsound_dirt_claw_medium_6", "volume": 0.11 },
{ "name": "cobblemon:stepsound/dirt/claw/medium/stepsound_dirt_claw_medium_7", "volume": 0.11 },
{ "name": "cobblemon:stepsound/dirt/claw/medium/stepsound_dirt_claw_medium_8", "volume": 0.11 }
]
},
"stepsound.stone.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/stone/claw/large/stepsound_stone_claw_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/stone/claw/large/stepsound_stone_claw_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/stone/claw/large/stepsound_stone_claw_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/stone/claw/large/stepsound_stone_claw_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/stone/claw/large/stepsound_stone_claw_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/stone/claw/large/stepsound_stone_claw_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/stone/claw/large/stepsound_stone_claw_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/stone/claw/large/stepsound_stone_claw_large_8", "volume": 0.22 }
]
},
"stepsound.stone.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/stone/claw/medium/stepsound_stone_claw_medium_1", "volume": 0.11 },
{ "name": "cobblemon:stepsound/stone/claw/medium/stepsound_stone_claw_medium_2", "volume": 0.11 },
{ "name": "cobblemon:stepsound/stone/claw/medium/stepsound_stone_claw_medium_3", "volume": 0.11 },
{ "name": "cobblemon:stepsound/stone/claw/medium/stepsound_stone_claw_medium_4", "volume": 0.11 },
{ "name": "cobblemon:stepsound/stone/claw/medium/stepsound_stone_claw_medium_5", "volume": 0.11 },
{ "name": "cobblemon:stepsound/stone/claw/medium/stepsound_stone_claw_medium_6", "volume": 0.11 },
{ "name": "cobblemon:stepsound/stone/claw/medium/stepsound_stone_claw_medium_7", "volume": 0.11 },
{ "name": "cobblemon:stepsound/stone/claw/medium/stepsound_stone_claw_medium_8", "volume": 0.11 }
]
},
"stepsound.sand.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/sand/claw/large/stepsound_sand_claw_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/sand/claw/large/stepsound_sand_claw_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/sand/claw/large/stepsound_sand_claw_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/sand/claw/large/stepsound_sand_claw_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/sand/claw/large/stepsound_sand_claw_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/sand/claw/large/stepsound_sand_claw_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/sand/claw/large/stepsound_sand_claw_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/sand/claw/large/stepsound_sand_claw_large_8", "volume": 0.22 }
]
},
"stepsound.sand.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/sand/claw/medium/stepsound_sand_claw_medium_1", "volume": 0.11 },
{ "name": "cobblemon:stepsound/sand/claw/medium/stepsound_sand_claw_medium_2", "volume": 0.11 },
{ "name": "cobblemon:stepsound/sand/claw/medium/stepsound_sand_claw_medium_3", "volume": 0.11 },
{ "name": "cobblemon:stepsound/sand/claw/medium/stepsound_sand_claw_medium_4", "volume": 0.11 },
{ "name": "cobblemon:stepsound/sand/claw/medium/stepsound_sand_claw_medium_5", "volume": 0.11 },
{ "name": "cobblemon:stepsound/sand/claw/medium/stepsound_sand_claw_medium_6", "volume": 0.11 },
{ "name": "cobblemon:stepsound/sand/claw/medium/stepsound_sand_claw_medium_7", "volume": 0.11 },
{ "name": "cobblemon:stepsound/sand/claw/medium/stepsound_sand_claw_medium_8", "volume": 0.11 }
]
},
"stepsound.snow.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/snow/claw/large/stepsound_snow_claw_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/claw/large/stepsound_snow_claw_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/claw/large/stepsound_snow_claw_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/claw/large/stepsound_snow_claw_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/claw/large/stepsound_snow_claw_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/claw/large/stepsound_snow_claw_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/claw/large/stepsound_snow_claw_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/snow/claw/large/stepsound_snow_claw_large_8", "volume": 0.22 }
]
},
"stepsound.snow.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/snow/claw/medium/stepsound_snow_claw_medium_1", "volume": 0.11 },
{ "name": "cobblemon:stepsound/snow/claw/medium/stepsound_snow_claw_medium_2", "volume": 0.11 },
{ "name": "cobblemon:stepsound/snow/claw/medium/stepsound_snow_claw_medium_3", "volume": 0.11 },
{ "name": "cobblemon:stepsound/snow/claw/medium/stepsound_snow_claw_medium_4", "volume": 0.11 },
{ "name": "cobblemon:stepsound/snow/claw/medium/stepsound_snow_claw_medium_5", "volume": 0.11 },
{ "name": "cobblemon:stepsound/snow/claw/medium/stepsound_snow_claw_medium_6", "volume": 0.11 },
{ "name": "cobblemon:stepsound/snow/claw/medium/stepsound_snow_claw_medium_7", "volume": 0.11 },
{ "name": "cobblemon:stepsound/snow/claw/medium/stepsound_snow_claw_medium_8", "volume": 0.11 }
]
},
"stepsound.wood.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/wood/claw/large/stepsound_wood_claw_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/wood/claw/large/stepsound_wood_claw_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/wood/claw/large/stepsound_wood_claw_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/wood/claw/large/stepsound_wood_claw_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/wood/claw/large/stepsound_wood_claw_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/wood/claw/large/stepsound_wood_claw_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/wood/claw/large/stepsound_wood_claw_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/wood/claw/large/stepsound_wood_claw_large_8", "volume": 0.22 }
]
},
"stepsound.wood.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/wood/claw/medium/stepsound_wood_claw_medium_1", "volume": 0.11 },
{ "name": "cobblemon:stepsound/wood/claw/medium/stepsound_wood_claw_medium_2", "volume": 0.11 },
{ "name": "cobblemon:stepsound/wood/claw/medium/stepsound_wood_claw_medium_3", "volume": 0.11 },
{ "name": "cobblemon:stepsound/wood/claw/medium/stepsound_wood_claw_medium_4", "volume": 0.11 },
{ "name": "cobblemon:stepsound/wood/claw/medium/stepsound_wood_claw_medium_5", "volume": 0.11 },
{ "name": "cobblemon:stepsound/wood/claw/medium/stepsound_wood_claw_medium_6", "volume": 0.11 },
{ "name": "cobblemon:stepsound/wood/claw/medium/stepsound_wood_claw_medium_7", "volume": 0.11 },
{ "name": "cobblemon:stepsound/wood/claw/medium/stepsound_wood_claw_medium_8", "volume": 0.11 }
]
},
"stepsound.mud.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/mud/claw/large/stepsound_mud_claw_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/claw/large/stepsound_mud_claw_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/claw/large/stepsound_mud_claw_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/claw/large/stepsound_mud_claw_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/claw/large/stepsound_mud_claw_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/claw/large/stepsound_mud_claw_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/claw/large/stepsound_mud_claw_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/mud/claw/large/stepsound_mud_claw_large_8", "volume": 0.22 }
]
},
"stepsound.mud.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/mud/claw/medium/stepsound_mud_claw_medium_1", "volume": 0.11 },
{ "name": "cobblemon:stepsound/mud/claw/medium/stepsound_mud_claw_medium_2", "volume": 0.11 },
{ "name": "cobblemon:stepsound/mud/claw/medium/stepsound_mud_claw_medium_3", "volume": 0.11 },
{ "name": "cobblemon:stepsound/mud/claw/medium/stepsound_mud_claw_medium_4", "volume": 0.11 },
{ "name": "cobblemon:stepsound/mud/claw/medium/stepsound_mud_claw_medium_5", "volume": 0.11 },
{ "name": "cobblemon:stepsound/mud/claw/medium/stepsound_mud_claw_medium_6", "volume": 0.11 },
{ "name": "cobblemon:stepsound/mud/claw/medium/stepsound_mud_claw_medium_7", "volume": 0.11 },
{ "name": "cobblemon:stepsound/mud/claw/medium/stepsound_mud_claw_medium_8", "volume": 0.11 }
]
},
"stepsound.glass.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/glass/claw/large/stepsound_glass_claw_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/glass/claw/large/stepsound_glass_claw_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/glass/claw/large/stepsound_glass_claw_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/glass/claw/large/stepsound_glass_claw_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/glass/claw/large/stepsound_glass_claw_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/glass/claw/large/stepsound_glass_claw_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/glass/claw/large/stepsound_glass_claw_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/glass/claw/large/stepsound_glass_claw_large_8", "volume": 0.22 }
]
},
"stepsound.glass.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/glass/claw/medium/stepsound_glass_claw_medium_1", "volume": 0.11 },
{ "name": "cobblemon:stepsound/glass/claw/medium/stepsound_glass_claw_medium_2", "volume": 0.11 },
{ "name": "cobblemon:stepsound/glass/claw/medium/stepsound_glass_claw_medium_3", "volume": 0.11 },
{ "name": "cobblemon:stepsound/glass/claw/medium/stepsound_glass_claw_medium_4", "volume": 0.11 },
{ "name": "cobblemon:stepsound/glass/claw/medium/stepsound_glass_claw_medium_5", "volume": 0.11 },
{ "name": "cobblemon:stepsound/glass/claw/medium/stepsound_glass_claw_medium_6", "volume": 0.11 },
{ "name": "cobblemon:stepsound/glass/claw/medium/stepsound_glass_claw_medium_7", "volume": 0.11 },
{ "name": "cobblemon:stepsound/glass/claw/medium/stepsound_glass_claw_medium_8", "volume": 0.11 }
]
},
"stepsound.metal.claw.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/metal/claw/large/stepsound_metal_claw_large_1", "volume": 0.22 },
{ "name": "cobblemon:stepsound/metal/claw/large/stepsound_metal_claw_large_2", "volume": 0.22 },
{ "name": "cobblemon:stepsound/metal/claw/large/stepsound_metal_claw_large_3", "volume": 0.22 },
{ "name": "cobblemon:stepsound/metal/claw/large/stepsound_metal_claw_large_4", "volume": 0.22 },
{ "name": "cobblemon:stepsound/metal/claw/large/stepsound_metal_claw_large_5", "volume": 0.22 },
{ "name": "cobblemon:stepsound/metal/claw/large/stepsound_metal_claw_large_6", "volume": 0.22 },
{ "name": "cobblemon:stepsound/metal/claw/large/stepsound_metal_claw_large_7", "volume": 0.22 },
{ "name": "cobblemon:stepsound/metal/claw/large/stepsound_metal_claw_large_8", "volume": 0.22 }
]
},
"stepsound.metal.claw.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/metal/claw/medium/stepsound_metal_claw_medium_1", "volume": 0.11 },
{ "name": "cobblemon:stepsound/metal/claw/medium/stepsound_metal_claw_medium_2", "volume": 0.11 },
{ "name": "cobblemon:stepsound/metal/claw/medium/stepsound_metal_claw_medium_3", "volume": 0.11 },
{ "name": "cobblemon:stepsound/metal/claw/medium/stepsound_metal_claw_medium_4", "volume": 0.11 },
{ "name": "cobblemon:stepsound/metal/claw/medium/stepsound_metal_claw_medium_5", "volume": 0.11 },
{ "name": "cobblemon:stepsound/metal/claw/medium/stepsound_metal_claw_medium_6", "volume": 0.11 },
{ "name": "cobblemon:stepsound/metal/claw/medium/stepsound_metal_claw_medium_7", "volume": 0.11 },
{ "name": "cobblemon:stepsound/metal/claw/medium/stepsound_metal_claw_medium_8", "volume": 0.11 }
]
},
"stepsound.leaves.universal.large": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/leaves/universal/large/stepsound_leaves_universal_large_1", "volume": 0.12 },
{ "name": "cobblemon:stepsound/leaves/universal/large/stepsound_leaves_universal_large_2", "volume": 0.12 },
{ "name": "cobblemon:stepsound/leaves/universal/large/stepsound_leaves_universal_large_3", "volume": 0.12 },
{ "name": "cobblemon:stepsound/leaves/universal/large/stepsound_leaves_universal_large_4", "volume": 0.12 },
{ "name": "cobblemon:stepsound/leaves/universal/large/stepsound_leaves_universal_large_5", "volume": 0.12 },
{ "name": "cobblemon:stepsound/leaves/universal/large/stepsound_leaves_universal_large_6", "volume": 0.12 },
{ "name": "cobblemon:stepsound/leaves/universal/large/stepsound_leaves_universal_large_7", "volume": 0.12 },
{ "name": "cobblemon:stepsound/leaves/universal/large/stepsound_leaves_universal_large_8", "volume": 0.12 }
]
},
"stepsound.leaves.universal.medium": {
"subtitle": "subtitles.block.generic.footsteps",
"sounds": [
{ "name": "cobblemon:stepsound/leaves/universal/medium/stepsound_leaves_universal_medium_1", "volume": 0.06 },
{ "name": "cobblemon:stepsound/leaves/universal/medium/stepsound_leaves_universal_medium_2", "volume": 0.06 },
{ "name": "cobblemon:stepsound/leaves/universal/medium/stepsound_leaves_universal_medium_3", "volume": 0.06 },
{ "name": "cobblemon:stepsound/leaves/universal/medium/stepsound_leaves_universal_medium_4", "volume": 0.06 },
{ "name": "cobblemon:stepsound/leaves/universal/medium/stepsound_leaves_universal_medium_5", "volume": 0.06 },
{ "name": "cobblemon:stepsound/leaves/universal/medium/stepsound_leaves_universal_medium_6", "volume": 0.06 },
{ "name": "cobblemon:stepsound/leaves/universal/medium/stepsound_leaves_universal_medium_7", "volume": 0.06 },
{ "name": "cobblemon:stepsound/leaves/universal/medium/stepsound_leaves_universal_medium_8", "volume": 0.06 }
]
},
"ride.loop.wind.mono": {
"sounds": [
{
Loaded 100 of 2770 files, more files were not shown because too many files have changed in this diff. Show more