mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-11-03 14:58:53 -05:00
Compare commits
127
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da76b2fb94 | ||
|
|
87d8197dd0 | ||
|
|
2ed6f89d09 | ||
|
|
5947468cd9 | ||
|
|
7ba1507ac8 | ||
|
|
9fdffdc392 | ||
|
|
6a01fe3863 | ||
|
|
9b5a153e3f | ||
|
|
67f906dec2 | ||
|
|
0570afbe05 | ||
|
|
dfba2d27ab | ||
|
|
9c7cd4b616 | ||
|
|
9fe0e9c87e | ||
|
|
bd0e5a44bd | ||
|
|
229ec4176b | ||
|
|
323413efdc | ||
|
|
a309cc2522 | ||
|
|
cb782a2aa1 | ||
|
|
2c58dcb8ef | ||
|
|
d91cd4322c | ||
|
|
e48e492392 | ||
|
|
1f93994eba | ||
|
|
5210121b3d | ||
|
|
7fa3bf24d1 | ||
|
|
1128d7edf3 | ||
|
|
eef50a7237 | ||
|
|
397d3c618d | ||
|
|
29f6feab6c | ||
|
|
ea5d3ae40f | ||
|
|
def975c03f | ||
|
|
e67567e8dc | ||
|
|
23a42a29b3 | ||
|
|
bacc482bf0 | ||
|
|
edb3f906f8 | ||
|
|
4171bf341b | ||
|
|
61d53f3052 | ||
|
|
2e88d971f7 | ||
|
|
bfc1c66097 | ||
|
|
13d9f84d8d | ||
|
|
148eb130d9 | ||
|
|
eb07b0e03f | ||
|
|
1b8d416962 | ||
|
|
3030b544b5 | ||
|
|
b890d662f6 | ||
|
|
2a9bbc1d68 | ||
|
|
735817869a | ||
|
|
488e6dcf7a | ||
|
|
a0f32ea444 | ||
|
|
b426df7271 | ||
|
|
1543e06a06 | ||
|
|
d7b4ccb1e5 | ||
|
|
dedd449329 | ||
|
|
38c589658f | ||
|
|
182e06205d | ||
|
|
4c391645fe | ||
|
|
79bf50004a | ||
|
|
2f961bd7bf | ||
|
|
b72244a986 | ||
|
|
6710f25190 | ||
|
|
4089e5d7a9 | ||
|
|
0a49b5b17b | ||
|
|
34c40de429 | ||
|
|
6d02144401 | ||
|
|
561687ce0f | ||
|
|
20973c6724 | ||
|
|
bf10a4dcef | ||
|
|
565987a780 | ||
|
|
4f9a6c8e98 | ||
|
|
3a3e92d441 | ||
|
|
bc0dc809f9 | ||
|
|
92310847aa | ||
|
|
5bdc59830c | ||
|
|
17f524d3da | ||
|
|
4d0de2bb45 | ||
|
|
b3b8f56bb8 | ||
|
|
f036b83693 | ||
|
|
73fb31c2fc | ||
|
|
381787f39d | ||
|
|
2cb942a24b | ||
|
|
c79cb5731e | ||
|
|
4760bb15a4 | ||
|
|
aac881f23c | ||
|
|
da19c51566 | ||
|
|
396ab13164 | ||
|
|
37dd354155 | ||
|
|
acb1ebda19 | ||
|
|
5dddc05626 | ||
|
|
99890671bd | ||
|
|
9451ac5f46 | ||
|
|
a8e4e21ba1 | ||
|
|
f555ba3703 | ||
|
|
37677b3730 | ||
|
|
2a298b2268 | ||
|
|
ad3f94fb80 | ||
|
|
719660798e | ||
|
|
8d973a09e1 | ||
|
|
3579a86cde | ||
|
|
ba96a6a205 | ||
|
|
f07d2a9a9a | ||
|
|
2469067fd4 | ||
|
|
c10c91d86a | ||
|
|
d5fd2e9a07 | ||
|
|
45cc0ba579 | ||
|
|
1880a0a24e | ||
|
|
5f3a0b96cc | ||
|
|
7ab1610700 | ||
|
|
daad9f6c00 | ||
|
|
2b234b740e | ||
|
|
39e3983020 | ||
|
|
9d58cdb21c | ||
|
|
f05e35e792 | ||
|
|
a333e68620 | ||
|
|
2c2791ec69 | ||
|
|
635b09d82f | ||
|
|
46c3ff9db4 | ||
|
|
8bfc95c23a | ||
|
|
99d05b6ef7 | ||
|
|
1c0a14c819 | ||
|
|
fe5cd58801 | ||
|
|
c3bd007f5a | ||
|
|
dba24e104e | ||
|
|
35815e371b | ||
|
|
d0f8ae0565 | ||
|
|
b2e21969ca | ||
|
|
ea57c233a3 | ||
|
|
0d39b47f22 | ||
|
|
9f3a279b03 |
No files matched your search
+24
-2
@@ -1,15 +1,37 @@
|
||||
# Changelog
|
||||
## [1.8.x (MONTH xth, 2026)](#1-8-x)
|
||||
## [1.9.0 (MONTH xth, 2026)](#1-9-0)
|
||||
|
||||
### Additions
|
||||
- Trainer bags and packs got added
|
||||
- You can craft and equip those to store additional items
|
||||
|
||||
### 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
|
||||
|
||||
### Particles
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Updated translations for:
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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,6 +23,8 @@ 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;
|
||||
@@ -56,6 +58,7 @@ 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;
|
||||
@@ -73,7 +76,7 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger, BagEntity {
|
||||
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@@ -107,6 +110,8 @@ 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_);
|
||||
}
|
||||
@@ -404,4 +409,37 @@ 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,17 +15,23 @@ 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;
|
||||
@@ -33,6 +39,9 @@ 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 {
|
||||
@@ -142,4 +151,25 @@ 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());
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ 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
|
||||
@@ -1577,6 +1578,12 @@ 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,6 +10,7 @@ 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
|
||||
@@ -20,8 +21,9 @@ import net.minecraft.world.inventory.MenuType
|
||||
|
||||
object CobblemonMenuType : PlatformRegistry<Registry<MenuType<*>>, ResourceKey<Registry<MenuType<*>>>, MenuType<*>>() {
|
||||
|
||||
val COOKING_POT = MenuType.register("cooking_pot_menu", ::CookingPotMenu)
|
||||
val COOKING_POT = MenuType.register("cooking_pot", ::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,6 +13,8 @@ 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
|
||||
@@ -42,14 +44,9 @@ import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureRangeHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureRangePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.AdjustPastureRangePacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.AdjustPastureRangeHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureConflictFlagHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureRecoveryHandler
|
||||
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundSeatAssignmentPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
|
||||
@@ -81,6 +78,8 @@ 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
|
||||
@@ -106,7 +105,6 @@ import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureRecoveryPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
|
||||
@@ -450,6 +448,7 @@ 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
|
||||
@@ -479,12 +478,10 @@ object CobblemonNetwork {
|
||||
|
||||
// Pasture
|
||||
list.add(PacketRegisterInfo(OpenPasturePacket.ID, OpenPasturePacket::decode, OpenPastureHandler))
|
||||
list.add(PacketRegisterInfo(UpdatePastureRangePacket.ID, UpdatePastureRangePacket::decode, UpdatePastureRangeHandler))
|
||||
list.add(PacketRegisterInfo(ClosePasturePacket.ID, ClosePasturePacket::decode, ClosePastureHandler))
|
||||
list.add(PacketRegisterInfo(PokemonPasturedPacket.ID, PokemonPasturedPacket::decode, PokemonPasturedHandler))
|
||||
list.add(PacketRegisterInfo(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler))
|
||||
list.add(PacketRegisterInfo(UpdatePastureConflictFlagPacket.ID, UpdatePastureConflictFlagPacket::decode, UpdatePastureConflictFlagHandler))
|
||||
list.add(PacketRegisterInfo(UpdatePastureRecoveryPacket.ID, UpdatePastureRecoveryPacket::decode, UpdatePastureRecoveryHandler))
|
||||
|
||||
// Orientation
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, ClientboundUpdateOrientationHandler))
|
||||
@@ -599,7 +596,6 @@ object CobblemonNetwork {
|
||||
|
||||
// Pasture
|
||||
list.add(PacketRegisterInfo(PasturePokemonPacket.ID, PasturePokemonPacket::decode, PasturePokemonHandler))
|
||||
list.add(PacketRegisterInfo(AdjustPastureRangePacket.ID, AdjustPastureRangePacket::decode, AdjustPastureRangeHandler))
|
||||
list.add(PacketRegisterInfo(UnpasturePokemonPacket.ID, UnpasturePokemonPacket::decode, UnpasturePokemonHandler))
|
||||
list.add(PacketRegisterInfo(UnpastureAllPokemonPacket.ID, UnpastureAllPokemonPacket::decode, UnpastureAllPokemonHandler))
|
||||
list.add(PacketRegisterInfo(SetPastureConflictPacket.ID, SetPastureConflictPacket::decode, SetPastureConflictHandler))
|
||||
@@ -649,6 +645,10 @@ 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 +656,7 @@ object CobblemonNetwork {
|
||||
// Habitat blocks
|
||||
list.add(PacketRegisterInfo(SaveHabitatBlockSettingsPacket.ID, SaveHabitatBlockSettingsPacket::decode, SaveHabitatBlockSettingsHandler))
|
||||
|
||||
// Debug / cheats
|
||||
// Debug
|
||||
list.add(PacketRegisterInfo(RequestOpenRidingStatsDebugGUIPacket.ID, RequestOpenRidingStatsDebugGUIPacket::decode, RequestOpenRidingStatsDebugGUIHandler))
|
||||
|
||||
|
||||
@@ -666,4 +666,4 @@ object CobblemonNetwork {
|
||||
fun sendPacketToPlayer(player: ServerPlayer, packet: NetworkPacket<*>) {
|
||||
Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,6 +321,19 @@ 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
|
||||
|
||||
+2
-11
@@ -15,13 +15,11 @@ import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WANDER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -71,14 +69,7 @@ class AirWanderTaskConfig : SingleTaskConfig {
|
||||
|
||||
val rotVec = entity.getViewVector(0F)
|
||||
pathCooldown.setWithExpiry(true, 60L)
|
||||
val tethering = (entity as? PokemonEntity)?.tethering
|
||||
val horizontal = horizontalRange.resolveInt(runtime)
|
||||
val vertical = verticalRange.resolveInt(runtime)
|
||||
val minUpwards = minUpwardsMovement.resolveInt(runtime)
|
||||
val minDownwards = minDownwardsMovement.resolveInt(runtime)
|
||||
val target = (0 until 10).asSequence()
|
||||
.mapNotNull { HoverRandomPos.getPos(entity, horizontal, vertical, rotVec.x, rotVec.y, 1.5707964f, minUpwards, minDownwards) }
|
||||
.firstOrNull { tethering?.canRoamTo(BlockPos.containing(it)) != false }
|
||||
val target = HoverRandomPos.getPos(entity, horizontalRange.resolveInt(runtime), verticalRange.resolveInt(runtime), rotVec.x, rotVec.y, 1.5707964f, minUpwardsMovement.resolveInt(runtime), minDownwardsMovement.resolveInt(runtime))
|
||||
?: return@Trigger false
|
||||
walkTarget.set(WalkTarget(target, speedMultiplier.resolveFloat(runtime), 3))
|
||||
lookTarget.set(BlockPosTracker(target))
|
||||
@@ -87,4 +78,4 @@ class AirWanderTaskConfig : SingleTaskConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -17,7 +17,6 @@ import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WA
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonWalkTarget
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
@@ -96,7 +95,6 @@ class WaterWanderTaskConfig : SingleTaskConfig {
|
||||
attempts++
|
||||
target = BehaviorUtils.getRandomSwimmablePos(entity, horizontalRange.resolveInt(mainThreadRuntime), verticalRange.resolveInt(mainThreadRuntime))
|
||||
?: continue
|
||||
if ((entity as? PokemonEntity)?.tethering?.canRoamTo(BlockPos.containing(target)) == false) continue
|
||||
pos = BlockPos.containing(target).takeIf(wanderControl::isSuitable)
|
||||
}
|
||||
|
||||
@@ -145,4 +143,4 @@ class WaterWanderTaskConfig : SingleTaskConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,14 @@
|
||||
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
|
||||
|
||||
/**
|
||||
@@ -31,9 +33,9 @@ interface TradeEvent {
|
||||
val tradeParticipant1: TradeParticipant
|
||||
|
||||
/**
|
||||
* The [Pokemon] being traded by the first participant.
|
||||
* All the [Pokemon] the first participant receives in the trade.
|
||||
*/
|
||||
val tradeParticipant1Pokemon: Pokemon
|
||||
val tradeParticipant1Pokemon: List<Pokemon>
|
||||
|
||||
/**
|
||||
* The second [TradeParticipant].
|
||||
@@ -41,9 +43,19 @@ interface TradeEvent {
|
||||
val tradeParticipant2: TradeParticipant
|
||||
|
||||
/**
|
||||
* The [Pokemon] being traded by the second participant.
|
||||
* All the [Pokemon] the second participant receives in the trade.
|
||||
*/
|
||||
val tradeParticipant2Pokemon: Pokemon
|
||||
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 }
|
||||
)
|
||||
|
||||
/**
|
||||
* Event fired when a trade is about to happen. Cancelling this event prevents the trade from occurring.
|
||||
@@ -53,16 +65,11 @@ interface TradeEvent {
|
||||
*/
|
||||
data class Pre(
|
||||
override val tradeParticipant1: TradeParticipant,
|
||||
override val tradeParticipant1Pokemon: Pokemon,
|
||||
override val tradeParticipant1Pokemon: List<Pokemon>,
|
||||
override val tradeParticipant2: TradeParticipant,
|
||||
override val tradeParticipant2Pokemon: Pokemon
|
||||
override val tradeParticipant2Pokemon: List<Pokemon>
|
||||
) : TradeEvent, Cancelable() {
|
||||
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 context = createContext()
|
||||
|
||||
val functions = moLangFunctionMap(
|
||||
cancelFunc
|
||||
@@ -77,15 +84,10 @@ interface TradeEvent {
|
||||
*/
|
||||
data class Post(
|
||||
override val tradeParticipant1: TradeParticipant,
|
||||
override val tradeParticipant1Pokemon: Pokemon,
|
||||
override val tradeParticipant1Pokemon: List<Pokemon>,
|
||||
override val tradeParticipant2: TradeParticipant,
|
||||
override val tradeParticipant2Pokemon: Pokemon
|
||||
override val tradeParticipant2Pokemon: List<Pokemon>
|
||||
) : TradeEvent {
|
||||
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 context = createContext()
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ object PastureLinkManager {
|
||||
fun getLinkByPlayer(player: ServerPlayer): PastureLink? {
|
||||
val link = getLinkByPlayerId(player.uuid)
|
||||
if (link != null) {
|
||||
if (player.level().dimension().location() != link.dimension || !link.pos.closerToCenterThan(player.position(), 10.0)) {
|
||||
if (!player.level().dimensionTypeRegistration().`is`(link.dimension) || !link.pos.closerToCenterThan(player.position(), 10.0)) {
|
||||
links.remove(player.uuid)
|
||||
return null
|
||||
}
|
||||
@@ -46,8 +46,8 @@ object PastureLinkManager {
|
||||
@JvmStatic
|
||||
fun removeAt(world: ServerLevel, pos: BlockPos) {
|
||||
links.removeIf { (uuid, pastureLink) ->
|
||||
val shouldRemove = world.dimension().location() == pastureLink.dimension && pastureLink.pos == pos
|
||||
if (shouldRemove) uuid.getPlayer()?.sendPacket(ClosePasturePacket())
|
||||
val shouldRemove = world.dimensionTypeRegistration().`is`(pastureLink.dimension) && pastureLink.pos == pos
|
||||
uuid.getPlayer()?.sendPacket(ClosePasturePacket())
|
||||
return@removeIf shouldRemove
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +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.pasture
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
|
||||
data class PastureRange(val north: Int, val east: Int, val south: Int, val west: Int) {
|
||||
fun isValid(maximum: Int): Boolean =
|
||||
listOf(north, east, south, west).all { it in 0..maximum } &&
|
||||
north.toLong() + south >= 8 && east.toLong() + west >= 8
|
||||
|
||||
operator fun get(direction: Direction): Int = when (direction) {
|
||||
Direction.NORTH -> north
|
||||
Direction.EAST -> east
|
||||
Direction.SOUTH -> south
|
||||
Direction.WEST -> west
|
||||
else -> error("Pasture range directions must be horizontal")
|
||||
}
|
||||
|
||||
fun adjusted(direction: Direction, amount: Int): PastureRange = when (direction) {
|
||||
Direction.NORTH -> copy(north = north + amount)
|
||||
Direction.EAST -> copy(east = east + amount)
|
||||
Direction.SOUTH -> copy(south = south + amount)
|
||||
Direction.WEST -> copy(west = west + amount)
|
||||
else -> this
|
||||
}
|
||||
|
||||
fun minPos(origin: BlockPos) = origin.offset(-west, 0, -north)
|
||||
fun maxPos(origin: BlockPos) = origin.offset(east, 0, south)
|
||||
|
||||
fun nearbyBlocks(origin: BlockPos, preferred: BlockPos, width: Double): Sequence<BlockPos> = sequence {
|
||||
val halfWidth = width / 2.0
|
||||
val minX = ceil(origin.x - west + halfWidth - 0.5).toInt()
|
||||
val maxX = floor(origin.x + east - halfWidth - 0.5).toInt()
|
||||
val minZ = ceil(origin.z - north + halfWidth - 0.5).toInt()
|
||||
val maxZ = floor(origin.z + south - halfWidth - 0.5).toInt()
|
||||
if (minX > maxX || minZ > maxZ) return@sequence
|
||||
|
||||
val centerX = preferred.x.coerceIn(minX, maxX)
|
||||
val centerZ = preferred.z.coerceIn(minZ, maxZ)
|
||||
for (distance in 0..16) {
|
||||
for (dx in -distance..distance) {
|
||||
val x = centerX + dx
|
||||
if (x !in minX..maxX) continue
|
||||
val dz = distance - abs(dx)
|
||||
val z = centerZ + dz
|
||||
if (z in minZ..maxZ) yield(BlockPos(x, origin.y, z))
|
||||
if (dz != 0 && centerZ - dz in minZ..maxZ) yield(BlockPos(x, origin.y, centerZ - dz))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeVarInt(north)
|
||||
buffer.writeVarInt(east)
|
||||
buffer.writeVarInt(south)
|
||||
buffer.writeVarInt(west)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MAX_DISTANCE = 64
|
||||
|
||||
fun fromBounds(origin: BlockPos, min: BlockPos, max: BlockPos) = PastureRange(
|
||||
origin.z - min.z, max.x - origin.x, max.z - origin.z, origin.x - min.x
|
||||
)
|
||||
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = PastureRange(
|
||||
buffer.readVarInt(), buffer.readVarInt(), buffer.readVarInt(), buffer.readVarInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -140,6 +140,20 @@ 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,6 +24,7 @@ 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
|
||||
@@ -31,13 +32,9 @@ 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.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.*
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
@@ -48,9 +45,11 @@ 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) {
|
||||
@@ -79,6 +78,14 @@ 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 {
|
||||
@@ -158,7 +165,12 @@ class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
|
||||
}
|
||||
val party = serverPlayerEntity.party()
|
||||
val pc = serverPlayerEntity.pc()
|
||||
val healPC = player.level().gameRules.getBoolean(CobblemonGameRules.HEALERS_HEAL_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)
|
||||
}
|
||||
|
||||
if (party.none() && (!healPC || pc.none())) {
|
||||
player.sendSystemMessage(lang("healingmachine.nopokemon").red(), true)
|
||||
@@ -183,6 +195,7 @@ 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
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.cobblemon.mod.common.util.rotateShape
|
||||
import com.mojang.serialization.MapCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.util.StringRepresentable
|
||||
@@ -282,13 +283,11 @@ class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWater
|
||||
pastureId = linkId,
|
||||
permissions = perms,
|
||||
limit = baseEntity.getMaxTethered(),
|
||||
tetheredPokemon = baseEntity.tetheredPokemon.mapNotNull { it.toDTO(player) },
|
||||
range = baseEntity.getRange(),
|
||||
facing = state.getValue(HorizontalDirectionalBlock.FACING)
|
||||
tetheredPokemon = baseEntity.tetheredPokemon.mapNotNull { it.toDTO(player) }
|
||||
)
|
||||
)
|
||||
|
||||
PastureLinkManager.createLink(player.uuid, PastureLink(linkId, pcId, world.dimension().location(), getBasePosition(state, pos), perms))
|
||||
PastureLinkManager.createLink(player.uuid, PastureLink(linkId, pcId, ResourceLocation.tryParse(world.dimensionTypeRegistration().registeredName)!!, getBasePosition(state, pos), perms))
|
||||
|
||||
world.playSoundServer(
|
||||
position = pos.bottomCenter,
|
||||
@@ -367,4 +366,4 @@ class PastureBlock(settings: Properties): BaseEntityBlock(settings), SimpleWater
|
||||
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,8 +160,8 @@ class TypeGemClusterBlock(
|
||||
&& state.getValue(STAGE) == 3) return false
|
||||
|
||||
val supportPos = pos.relative(state.getValue(FACING).opposite)
|
||||
val supportBlock = level.getBlockState(supportPos).block
|
||||
return CobblemonBlocks.typeGemBlocks().containsValue(supportBlock) || (supportBlock == CobblemonBlocks.TYPE_GEM_CORE) // Cannot grow if not on any gem blocks
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -51,10 +51,20 @@ 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("cobblemon:fairy_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_FAIRY,
|
||||
ResourceLocation.parse("minecraft:amethyst_block") to Blocks.SMALL_AMETHYST_BUD
|
||||
)
|
||||
}
|
||||
|
||||
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>()
|
||||
@@ -85,12 +95,16 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
|
||||
Direction.entries.forEach {
|
||||
if (random.nextFloat() < Cobblemon.config.typeGemGrowthChance) {
|
||||
val faceState = level.getBlockState(pos.relative(it))
|
||||
val randomGrowthType = decideClusterGrowthType(level, pos)
|
||||
val newState = BLOCK_TO_CLUSTER[BuiltInRegistries.BLOCK.getKey(state.block)]?.defaultBlockState()
|
||||
var 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)
|
||||
}
|
||||
@@ -132,7 +146,7 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
|
||||
if (!visited.add(clusterPos)) continue
|
||||
|
||||
val clusterState = level.getBlockState(clusterPos)
|
||||
if (clusterState.block == expectedCluster) {
|
||||
if (clusterState.block == expectedCluster && clusterState.hasProperty(GROWTH_TYPE)) {
|
||||
clusters += clusterState to clusterPos
|
||||
}
|
||||
}
|
||||
@@ -178,13 +192,41 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
|
||||
Direction.entries.forEach { direction ->
|
||||
val relativePos = pos.relative(direction)
|
||||
val relativeState = level.getBlockState(relativePos)
|
||||
val clusterBlock = relativeState.block as? TypeGemClusterBlock ?: return@forEach
|
||||
|
||||
if ((relativeState.getValue(DirectionalBlock.FACING) == direction &&
|
||||
random.nextFloat() < Cobblemon.config.typeGemGrowthChance) || forceGrow
|
||||
) {
|
||||
clusterBlock.advanceGrowth(relativeState, level, relativePos, random)
|
||||
val matchesFace = relativeState.hasProperty(DirectionalBlock.FACING)
|
||||
&& relativeState.getValue(DirectionalBlock.FACING) == direction
|
||||
if (!(forceGrow || (matchesFace && random.nextFloat() < Cobblemon.config.typeGemGrowthChance))) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+64
-219
@@ -14,19 +14,15 @@ import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.api.pasture.PastureLinkManager
|
||||
import com.cobblemon.mod.common.api.pasture.PastureRange
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
import com.cobblemon.mod.common.api.text.italicise
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.block.PastureBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureRecoveryPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
@@ -43,6 +39,7 @@ import net.minecraft.core.Vec3i
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.NbtUtils
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.tags.FluidTags
|
||||
@@ -51,61 +48,38 @@ import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.entity.EntityTypeTest
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
BlockEntity(CobblemonBlockEntities.PASTURE, pos, state) {
|
||||
open class Tethering(
|
||||
var minRoamPos: BlockPos,
|
||||
var maxRoamPos: BlockPos,
|
||||
val minRoamPos: BlockPos,
|
||||
val maxRoamPos: BlockPos,
|
||||
val playerId: UUID,
|
||||
val playerName: String,
|
||||
val tetheringId: UUID,
|
||||
val pokemonId: UUID,
|
||||
val pcId: UUID,
|
||||
var entityId: Int,
|
||||
val pasturePos: BlockPos,
|
||||
var entityUuid: UUID? = null,
|
||||
var lastEntityPos: BlockPos? = null,
|
||||
var respawnAt: Long = 0L,
|
||||
var healingAfterFaint: Boolean = false,
|
||||
var conflictEnabled: Boolean? = null
|
||||
val entityId: Int,
|
||||
val pasturePos: BlockPos
|
||||
) {
|
||||
fun getPokemon(): Pokemon? {
|
||||
val srv = server() ?: return null
|
||||
val pc = Cobblemon.storage.getPC(pcId, srv.registryAccess())
|
||||
return pc[pokemonId]
|
||||
}
|
||||
val box get() = AABB(minRoamPos.toVec3d(), maxRoamPos.toVec3d())
|
||||
fun canRoamTo(x: Double, z: Double) = x >= minRoamPos.x && x < maxRoamPos.x && z >= minRoamPos.z && z < maxRoamPos.z
|
||||
open fun canRoamTo(pos: BlockPos) = canRoamTo(pos.x + 0.5, pos.z + 0.5)
|
||||
|
||||
internal fun beginRecovery(now: Long, fainted: Boolean) {
|
||||
if (fainted && !healingAfterFaint) {
|
||||
healingAfterFaint = true
|
||||
respawnAt = now + FAINT_COOLDOWN
|
||||
} else if (respawnAt == 0L) {
|
||||
respawnAt = now + MISSING_ENTITY_COOLDOWN
|
||||
}
|
||||
}
|
||||
val box = AABB(minRoamPos.toVec3d(), maxRoamPos.toVec3d())
|
||||
open fun canRoamTo(pos: BlockPos) = box.contains(pos.center)
|
||||
|
||||
fun toDTO(player: ServerPlayer): OpenPasturePacket.PasturePokemonDataDTO? {
|
||||
val pokemon = getPokemon() ?: return null
|
||||
val entity = pokemon.entity
|
||||
|
||||
val behaviourFlags = (entity?.getActiveBehaviourFlags() ?: emptySet()).toMutableSet()
|
||||
when (conflictEnabled) {
|
||||
true -> behaviourFlags.add(PokemonBehaviourFlag.PASTURE_CONFLICT)
|
||||
false -> behaviourFlags.remove(PokemonBehaviourFlag.PASTURE_CONFLICT)
|
||||
null -> Unit
|
||||
}
|
||||
val behaviourFlags = entity?.getActiveBehaviourFlags() ?: emptySet()
|
||||
|
||||
return OpenPasturePacket.PasturePokemonDataDTO(
|
||||
pokemonId = pokemonId,
|
||||
@@ -117,16 +91,12 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
heldItem = pokemon.heldItem(),
|
||||
level = pokemon.level,
|
||||
entityKnown = (entity?.tethering?.tetheringId == tetheringId),
|
||||
behaviourFlags = behaviourFlags,
|
||||
healingAfterFaint = healingAfterFaint,
|
||||
respawnAt = respawnAt
|
||||
behaviourFlags = behaviourFlags
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FAINT_COOLDOWN = 24000L
|
||||
private const val MISSING_ENTITY_COOLDOWN = 200L
|
||||
internal val TICKER = BlockEntityTicker<PokemonPastureBlockEntity> { world, _, _, blockEntity ->
|
||||
if (world.isClientSide) return@BlockEntityTicker
|
||||
blockEntity.ticksUntilCheck--
|
||||
@@ -164,26 +134,6 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
|
||||
fun getMaxTethered() = Cobblemon.config.defaultPasturedPokemonLimit
|
||||
|
||||
fun getRange() = PastureRange.fromBounds(blockPos, minRoamPos, maxRoamPos)
|
||||
|
||||
fun setRange(range: PastureRange) {
|
||||
minRoamPos = range.minPos(blockPos).atY(minRoamPos.y)
|
||||
maxRoamPos = range.maxPos(blockPos).atY(maxRoamPos.y)
|
||||
tetheredPokemon.forEach { tethering ->
|
||||
tethering.minRoamPos = minRoamPos
|
||||
tethering.maxRoamPos = maxRoamPos
|
||||
tethering.getPokemon()?.entity?.let { entity ->
|
||||
if (entity.tethering?.tetheringId == tethering.tetheringId) {
|
||||
entity.tethering = tethering
|
||||
entity.navigation.stop()
|
||||
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
entity.checkPastureTether()
|
||||
}
|
||||
}
|
||||
}
|
||||
setChanged()
|
||||
}
|
||||
|
||||
fun canAddPokemon(player: ServerPlayer, pokemon: Pokemon, maxPerPlayer: Int): Boolean {
|
||||
val forThisPlayer = tetheredPokemon.count { it.playerId == player.uuid }
|
||||
// Shouldn't be possible, client should've prevented it
|
||||
@@ -208,64 +158,57 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
|
||||
|
||||
fun tether(player: ServerPlayer, pokemon: Pokemon, directionToBehind: Direction): Boolean {
|
||||
val tethering = Tethering(
|
||||
minRoamPos, maxRoamPos, player.uuid, player.gameProfile.name, UUID.randomUUID(),
|
||||
pokemon.uuid, Cobblemon.storage.getPC(player).uuid, -1, blockPos
|
||||
)
|
||||
if (!spawnPokemon(pokemon, tethering, directionToBehind)) return false
|
||||
pokemon.tetheringId = tethering.tetheringId
|
||||
pokemon.onChange()
|
||||
tetheredPokemon.add(tethering)
|
||||
tethering.toDTO(player)?.let { player.sendPacket(PokemonPasturedPacket(it)) }
|
||||
setChanged()
|
||||
CobblemonCriteria.PASTURE_USE.trigger(player, pokemon)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun spawnPokemon(pokemon: Pokemon, tethering: Tethering, directionToBehind: Direction): Boolean {
|
||||
val world = level ?: return false
|
||||
val entity = PokemonEntity(world, pokemon = pokemon)
|
||||
entity.refreshDimensions()
|
||||
val position = findSpawnPosition(entity, tethering.lastEntityPos, directionToBehind) ?: return false
|
||||
entity.setPos(position)
|
||||
entity.beamMode = 2
|
||||
entity.tethering = tethering
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.PASTURE_CONFLICT, tethering.conflictEnabled == true)
|
||||
if (!world.addFreshEntity(entity)) return false
|
||||
if (tethering.conflictEnabled == true) entity.remakeBrain()
|
||||
tethering.entityId = entity.id
|
||||
tethering.entityUuid = entity.uuid
|
||||
tethering.lastEntityPos = entity.blockPosition()
|
||||
tethering.respawnAt = 0L
|
||||
syncRecovery(tethering)
|
||||
afterOnServer(seconds = 0.5F) {
|
||||
if (!entity.isRemoved && entity.pokemon.shiny) {
|
||||
SpawnSnowstormEntityParticlePacket(cobblemonResource("shiny_ring"), entity.id, listOf("shiny_particles", "middle"))
|
||||
.sendToPlayersAround(entity.x, entity.y, entity.z, 64.0, entity.level().dimension())
|
||||
}
|
||||
entity.after(seconds = SendOutPokemonHandler.SEND_OUT_DURATION) {
|
||||
entity.beamMode = 0
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
val width = entity.boundingBox.xsize
|
||||
|
||||
fun findSpawnPosition(entity: PokemonEntity, preferred: BlockPos? = null, direction: Direction = blockState.getValue(HorizontalDirectionalBlock.FACING)): Vec3? {
|
||||
val world = level ?: return null
|
||||
val dimensions = entity.getDimensions(Pose.STANDING)
|
||||
val idealPlace = preferred ?: blockPos.offset(direction.normal.multiply(ceil(dimensions.width / 2.0).toInt() + 1))
|
||||
for (candidate in getRange().nearbyBlocks(blockPos, idealPlace, dimensions.width.toDouble())) {
|
||||
if (!world.hasChunkAt(candidate)) continue
|
||||
val box = dimensions.makeBoundingBox(candidate.center.subtract(0.0, 0.5, 0.0))
|
||||
val fixedPosition = makeSuitableY(world, candidate, entity, box) ?: continue
|
||||
val position = fixedPosition.center.subtract(0.0, 0.5, 0.0)
|
||||
val spawnBox = dimensions.makeBoundingBox(position)
|
||||
if (world.noCollision(entity, spawnBox) &&
|
||||
world.getEntitiesOfClass(PokemonEntity::class.java, spawnBox) { it != entity }.isEmpty()) {
|
||||
return position
|
||||
val idealPlace = blockPos.offset(directionToBehind.normal.multiply(ceil(width).toInt() + 1))
|
||||
var box = entity.getDimensions(Pose.STANDING).makeBoundingBox(idealPlace.center.subtract(0.0, 0.5, 0.0))
|
||||
|
||||
for (i in 0..5) {
|
||||
box = box.move(directionToBehind.normal.x.toDouble(), 0.0, directionToBehind.normal.z.toDouble())
|
||||
val fixedPosition = makeSuitableY(world, idealPlace.offset(directionToBehind.normal.multiply(i + 1)), entity, box)
|
||||
if (fixedPosition != null) {
|
||||
entity.setPos(fixedPosition.center.subtract(0.0, 0.5, 0.0))
|
||||
val pc = Cobblemon.storage.getPC(player)
|
||||
entity.beamMode = 2
|
||||
afterOnServer(seconds = 0.5F) {
|
||||
if(entity.pokemon.shiny) {
|
||||
SpawnSnowstormEntityParticlePacket(cobblemonResource("shiny_ring"), entity.id, listOf("shiny_particles", "middle"))
|
||||
.sendToPlayersAround(entity.x, entity.y, entity.z, 64.0, entity.level().dimension())
|
||||
}
|
||||
entity.after(seconds = SendOutPokemonHandler.SEND_OUT_DURATION) {
|
||||
entity.beamMode = 0
|
||||
}
|
||||
}
|
||||
if (world.addFreshEntity(entity)) {
|
||||
val tethering = Tethering(
|
||||
minRoamPos = minRoamPos,
|
||||
maxRoamPos = maxRoamPos,
|
||||
playerId = player.uuid,
|
||||
playerName = player.gameProfile.name,
|
||||
tetheringId = UUID.randomUUID(),
|
||||
pokemonId = pokemon.uuid,
|
||||
pcId = pc.uuid,
|
||||
entityId = entity.id,
|
||||
pasturePos = blockPos
|
||||
)
|
||||
pokemon.tetheringId = tethering.tetheringId
|
||||
tetheredPokemon.add(tethering)
|
||||
entity.tethering = tethering
|
||||
tethering.toDTO(player)?.let { player.sendPacket(PokemonPasturedPacket(it)) }
|
||||
setChanged()
|
||||
CobblemonCriteria.PASTURE_USE.trigger(player, pokemon)
|
||||
return true
|
||||
} else {
|
||||
Cobblemon.LOGGER.warn("Couldn't spawn pastured Pokémon for some reason")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun togglePastureOn(on: Boolean) {
|
||||
@@ -346,7 +289,6 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
}
|
||||
|
||||
fun checkPokemon() {
|
||||
val world = level as? ServerLevel ?: return
|
||||
val deadLinks = mutableListOf<UUID>()
|
||||
tetheredPokemon.forEach {
|
||||
val pokemon = it.getPokemon()
|
||||
@@ -354,8 +296,6 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
deadLinks.add(it.pokemonId)
|
||||
} else if (pokemon.tetheringId == null || pokemon.tetheringId != it.tetheringId) {
|
||||
deadLinks.add(it.pokemonId)
|
||||
} else {
|
||||
checkDeployment(world, it, pokemon)
|
||||
}
|
||||
}
|
||||
deadLinks.forEach(::releasePokemon)
|
||||
@@ -363,85 +303,6 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
setChanged()
|
||||
}
|
||||
|
||||
private fun checkDeployment(world: ServerLevel, tethering: Tethering, pokemon: Pokemon) {
|
||||
val now = world.gameTime
|
||||
if (pokemon.isFainted() && !tethering.healingAfterFaint) {
|
||||
tethering.beginRecovery(now, fainted = true)
|
||||
syncRecovery(tethering)
|
||||
}
|
||||
val entity = (pokemon.entity ?: tethering.entityUuid?.let(world::getEntity) as? PokemonEntity)
|
||||
?.takeIf { !it.isRemoved && it.tethering?.tetheringId == tethering.tetheringId }
|
||||
if (tethering.conflictEnabled == null && entity != null) {
|
||||
tethering.conflictEnabled = entity.getBehaviourFlag(PokemonBehaviourFlag.PASTURE_CONFLICT)
|
||||
}
|
||||
if (entity != null && pokemon.isFainted()) entity.discard()
|
||||
if (entity != null && !entity.isRemoved) {
|
||||
if (tethering.conflictEnabled != null && entity.getBehaviourFlag(PokemonBehaviourFlag.PASTURE_CONFLICT) != tethering.conflictEnabled) {
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.PASTURE_CONFLICT, tethering.conflictEnabled == true)
|
||||
entity.remakeBrain()
|
||||
}
|
||||
tethering.entityUuid = entity.uuid
|
||||
tethering.lastEntityPos = entity.blockPosition()
|
||||
entity.tethering = tethering
|
||||
if (tethering.respawnAt != 0L || tethering.healingAfterFaint) {
|
||||
tethering.respawnAt = 0L
|
||||
tethering.healingAfterFaint = false
|
||||
syncRecovery(tethering)
|
||||
}
|
||||
return
|
||||
}
|
||||
// A Pokémon in an unloaded chunk is still deployed. Never create its replacement.
|
||||
val lastPosition = tethering.lastEntityPos
|
||||
if (lastPosition != null) {
|
||||
if (!world.hasChunkAt(lastPosition)) return
|
||||
}
|
||||
// The last saved position may predate a chunk crossing. Require the entire range
|
||||
// to be entity-ticking before deciding that its missing Pokémon has disappeared.
|
||||
for (chunkX in (minRoamPos.x shr 4)..(maxRoamPos.x shr 4)) {
|
||||
for (chunkZ in (minRoamPos.z shr 4)..(maxRoamPos.z shr 4)) {
|
||||
if (!world.isPositionEntityTicking(BlockPos(chunkX shl 4, blockPos.y, chunkZ shl 4))) return
|
||||
}
|
||||
}
|
||||
if (tethering.respawnAt == 0L) {
|
||||
tethering.beginRecovery(now, fainted = false)
|
||||
syncRecovery(tethering)
|
||||
return
|
||||
}
|
||||
if (now < tethering.respawnAt) return
|
||||
if (tethering.healingAfterFaint) {
|
||||
pokemon.heal()
|
||||
if (pokemon.isFainted()) return
|
||||
tethering.healingAfterFaint = false
|
||||
syncRecovery(tethering)
|
||||
}
|
||||
val radius = Cobblemon.config.pastureMaxWanderDistance.toDouble()
|
||||
val nearby = world.getEntitiesOfClass(PokemonEntity::class.java, AABB.ofSize(blockPos.toVec3d(), radius * 2, world.height.toDouble(), radius * 2)).size
|
||||
val chunkDiameter = (radius / 16) * 2
|
||||
if (nearby >= Cobblemon.config.pastureMaxPerChunk * chunkDiameter * chunkDiameter ||
|
||||
!spawnPokemon(pokemon, tethering, blockState.getValue(HorizontalDirectionalBlock.FACING))) {
|
||||
tethering.respawnAt = now + MISSING_ENTITY_COOLDOWN
|
||||
syncRecovery(tethering)
|
||||
}
|
||||
}
|
||||
|
||||
private fun syncRecovery(tethering: Tethering) {
|
||||
val world = level as? ServerLevel ?: return
|
||||
val packet = UpdatePastureRecoveryPacket(tethering.pokemonId, tethering.healingAfterFaint, tethering.respawnAt)
|
||||
world.server.playerList.players.filter(::isPlayerViewing).forEach { it.sendPacket(packet) }
|
||||
}
|
||||
|
||||
fun setConflict(tethering: Tethering, enabled: Boolean) {
|
||||
tethering.conflictEnabled = enabled
|
||||
tethering.getPokemon()?.entity?.takeIf { it.tethering?.tetheringId == tethering.tetheringId }?.let {
|
||||
it.setBehaviourFlag(PokemonBehaviourFlag.PASTURE_CONFLICT, enabled)
|
||||
it.remakeBrain()
|
||||
}
|
||||
setChanged()
|
||||
val world = level as? ServerLevel ?: return
|
||||
val packet = UpdatePastureConflictFlagPacket(tethering.pokemonId, enabled)
|
||||
world.server.playerList.players.filter(::isPlayerViewing).forEach { it.sendPacket(packet) }
|
||||
}
|
||||
|
||||
fun onBroken() {
|
||||
if (level is ServerLevel) {
|
||||
tetheredPokemon.toList().forEach { releasePokemon(it.pokemonId) }
|
||||
@@ -451,10 +312,7 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
|
||||
fun releasePokemon(pokemonId: UUID) {
|
||||
val tethering = tetheredPokemon.find { it.pokemonId == pokemonId } ?: return
|
||||
tethering.getPokemon()?.let { pokemon ->
|
||||
pokemon.tetheringId = null
|
||||
pokemon.onChange()
|
||||
}
|
||||
tethering.getPokemon()?.tetheringId = null
|
||||
tetheredPokemon.remove(tethering)
|
||||
setChanged()
|
||||
}
|
||||
@@ -462,10 +320,7 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
fun releaseAllPokemon(playerId: UUID): List<UUID> {
|
||||
val unpastured = mutableListOf<UUID>()
|
||||
tetheredPokemon.filter { it.playerId == playerId }.forEach {
|
||||
it.getPokemon()?.let { pokemon ->
|
||||
pokemon.tetheringId = null
|
||||
pokemon.onChange()
|
||||
}
|
||||
it.getPokemon()?.tetheringId = null
|
||||
tetheredPokemon.remove(it)
|
||||
unpastured.add(it.pokemonId)
|
||||
}
|
||||
@@ -488,7 +343,9 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
|
||||
private fun isPlayerViewing(player: ServerPlayer): Boolean {
|
||||
val pastureLink = PastureLinkManager.getLinkByPlayer(player)
|
||||
return pastureLink != null && pastureLink.pos == blockPos && pastureLink.dimension == player.level().dimension().location()
|
||||
return pastureLink != null && pastureLink.pos == blockPos && pastureLink.dimension == ResourceLocation.tryParse(
|
||||
player.level().dimensionTypeRegistration().registeredName // todo (techdaan): confirm this is good
|
||||
)
|
||||
}
|
||||
|
||||
override fun loadAdditional(nbt: CompoundTag, registryLookup: HolderLookup.Provider) {
|
||||
@@ -496,9 +353,6 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
val list = nbt.getList(DataKeys.TETHER_POKEMON, CompoundTag.TAG_COMPOUND.toInt())
|
||||
this.ownerId = if (nbt.hasUUID(DataKeys.TETHER_OWNER_ID)) nbt.getUUID(DataKeys.TETHER_OWNER_ID) else null
|
||||
this.ownerName = nbt.getString(DataKeys.TETHER_OWNER_NAME).takeIf { it.isNotEmpty() } ?: ""
|
||||
this.minRoamPos = NbtUtils.readBlockPos(nbt, DataKeys.TETHER_MIN_ROAM_POS).orElse(minRoamPos)
|
||||
this.maxRoamPos = NbtUtils.readBlockPos(nbt, DataKeys.TETHER_MAX_ROAM_POS).orElse(maxRoamPos)
|
||||
tetheredPokemon.clear()
|
||||
for (tetheringNBT in list) {
|
||||
tetheringNBT as CompoundTag
|
||||
val tetheringId = tetheringNBT.getUUID(DataKeys.TETHERING_ID)
|
||||
@@ -511,20 +365,17 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
minRoamPos = minRoamPos,
|
||||
maxRoamPos = maxRoamPos,
|
||||
playerId = playerId,
|
||||
playerName = tetheringNBT.getString("PlayerName").ifEmpty { ownerName },
|
||||
playerName = ownerName,
|
||||
tetheringId = tetheringId,
|
||||
pokemonId = pokemonId,
|
||||
pcId = pcId,
|
||||
entityId = entityId,
|
||||
pasturePos = blockPos,
|
||||
entityUuid = if (tetheringNBT.hasUUID("EntityUUID")) tetheringNBT.getUUID("EntityUUID") else null,
|
||||
lastEntityPos = NbtUtils.readBlockPos(tetheringNBT, "LastEntityPos").orElse(null),
|
||||
respawnAt = tetheringNBT.getLong("RespawnAt"),
|
||||
healingAfterFaint = tetheringNBT.getBoolean("HealingAfterFaint"),
|
||||
conflictEnabled = if (tetheringNBT.contains("PastureConflict")) tetheringNBT.getBoolean("PastureConflict") else null
|
||||
pasturePos = blockPos
|
||||
)
|
||||
)
|
||||
}
|
||||
this.minRoamPos = NbtUtils.readBlockPos(nbt, DataKeys.TETHER_MIN_ROAM_POS).get()
|
||||
this.maxRoamPos = NbtUtils.readBlockPos(nbt, DataKeys.TETHER_MAX_ROAM_POS).get()
|
||||
}
|
||||
|
||||
override fun saveAdditional(nbt: CompoundTag, registryLookup: HolderLookup.Provider) {
|
||||
@@ -537,12 +388,6 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
tetheringNBT.putUUID(DataKeys.POKEMON_UUID, tethering.pokemonId)
|
||||
tetheringNBT.putUUID(DataKeys.PC_ID, tethering.pcId)
|
||||
tetheringNBT.putInt(DataKeys.TETHERING_ENTITY_ID, tethering.entityId)
|
||||
tetheringNBT.putString("PlayerName", tethering.playerName)
|
||||
tethering.entityUuid?.let { tetheringNBT.putUUID("EntityUUID", it) }
|
||||
tethering.lastEntityPos?.let { tetheringNBT.put("LastEntityPos", NbtUtils.writeBlockPos(it)) }
|
||||
tetheringNBT.putLong("RespawnAt", tethering.respawnAt)
|
||||
tetheringNBT.putBoolean("HealingAfterFaint", tethering.healingAfterFaint)
|
||||
tethering.conflictEnabled?.let { tetheringNBT.putBoolean("PastureConflict", it) }
|
||||
list.add(tetheringNBT)
|
||||
}
|
||||
nbt.put(DataKeys.TETHER_POKEMON, list)
|
||||
@@ -551,4 +396,4 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
ownerId?.let { nbt.putUUID(DataKeys.TETHER_OWNER_ID, it) }
|
||||
nbt.putString(DataKeys.TETHER_OWNER_NAME, this.ownerName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,13 @@
|
||||
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
|
||||
@@ -103,9 +106,33 @@ 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,6 +27,7 @@ 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
|
||||
@@ -46,6 +47,7 @@ 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
|
||||
@@ -391,7 +393,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,
|
||||
@@ -419,7 +421,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,
|
||||
@@ -539,14 +541,17 @@ 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() {
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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) {}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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) {}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
+2
-8
@@ -11,8 +11,6 @@ package com.cobblemon.mod.common.client.gui.pasture
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.pasture.PasturePermissions
|
||||
import com.cobblemon.mod.common.api.pasture.PastureRange
|
||||
import net.minecraft.core.Direction
|
||||
import com.cobblemon.mod.common.api.reactive.SettableObservable
|
||||
import com.cobblemon.mod.common.client.gui.pc.PCGUIConfiguration
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
@@ -23,9 +21,7 @@ class PasturePCGUIConfiguration(
|
||||
val pastureId: UUID,
|
||||
val limit: Int,
|
||||
val pasturedPokemon: SettableObservable<List<OpenPasturePacket.PasturePokemonDataDTO>>,
|
||||
var permissions: PasturePermissions,
|
||||
var range: PastureRange,
|
||||
val facing: Direction
|
||||
var permissions: PasturePermissions
|
||||
) : PCGUIConfiguration(
|
||||
exitFunction = { it.closeNormally(unlink = true) },
|
||||
showParty = false,
|
||||
@@ -36,6 +32,4 @@ class PasturePCGUIConfiguration(
|
||||
}
|
||||
},
|
||||
canSelect = { pokemon -> !pokemon.isFainted() && pokemon.tetheringId == null }
|
||||
) {
|
||||
var editingRange = false
|
||||
}
|
||||
)
|
||||
+14
-23
@@ -58,7 +58,6 @@ class PasturePokemonScrollList(
|
||||
private val scrollOverlayResource = cobblemonResource("textures/gui/pasture/pasture_scroll_overlay.png")
|
||||
private val slotResource = cobblemonResource("textures/gui/pasture/pasture_slot.png")
|
||||
private val slotOwnerResource = cobblemonResource("textures/gui/pasture/pasture_slot_owner.png")
|
||||
private val slotFaintedResource = cobblemonResource("textures/gui/pasture/pasture_slot_fainted.png")
|
||||
}
|
||||
|
||||
private var scrolling = false
|
||||
@@ -195,7 +194,7 @@ class PasturePokemonScrollList(
|
||||
}
|
||||
)
|
||||
|
||||
override fun getNarration() = if (pokemon.healingAfterFaint) lang("ui.pasture.fainted").append(" ").append(pokemon.displayName) else pokemon.displayName
|
||||
override fun getNarration() = pokemon.displayName
|
||||
|
||||
override fun render(
|
||||
context: GuiGraphics,
|
||||
@@ -215,7 +214,7 @@ class PasturePokemonScrollList(
|
||||
val matrixStack = context.pose()
|
||||
blitk(
|
||||
matrixStack = matrixStack,
|
||||
texture = if (pokemon.healingAfterFaint) slotFaintedResource else if (isOwned()) slotOwnerResource else slotResource,
|
||||
texture = if (isOwned()) slotOwnerResource else slotResource,
|
||||
x = x,
|
||||
y = y,
|
||||
height = SLOT_HEIGHT,
|
||||
@@ -235,8 +234,7 @@ class PasturePokemonScrollList(
|
||||
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
|
||||
state = state,
|
||||
partialTicks = partialTicks,
|
||||
scale = 4.5F,
|
||||
a = if (pokemon.healingAfterFaint) 0.7F else 1F
|
||||
scale = 4.5F
|
||||
)
|
||||
matrixStack.popPose()
|
||||
|
||||
@@ -251,21 +249,14 @@ class PasturePokemonScrollList(
|
||||
)
|
||||
}
|
||||
|
||||
val recovering = pokemon.healingAfterFaint || pokemon.respawnAt > 0L
|
||||
if (recovering) {
|
||||
if (!pokemon.healingAfterFaint) {
|
||||
drawScaledText(context, text = lang("ui.pasture.returning"),
|
||||
x = x + 18, y = y + 7, scale = SCALE, colour = 0xFFFF8585.toInt(), shadow = true)
|
||||
}
|
||||
val remainingTicks = (pokemon.respawnAt - (client.level?.gameTime ?: 0L)).coerceAtLeast(0L)
|
||||
val seconds = (remainingTicks + 19L) / 20L
|
||||
val timer = if (remainingTicks == 0L) lang("ui.pasture.ready") else "%d:%02d".format(seconds / 60L, seconds % 60L).text()
|
||||
drawScaledTextJustifiedRight(context = context, text = timer, x = x + 59, y = y + 17,
|
||||
shadow = true, scale = SCALE)
|
||||
} else {
|
||||
drawScaledTextJustifiedRight(context = context, text = lang("ui.lv.number", pokemon.level),
|
||||
x = x + 59, y = y + 17, shadow = true, scale = SCALE)
|
||||
}
|
||||
drawScaledTextJustifiedRight(
|
||||
context = context,
|
||||
text = lang("ui.lv.number", pokemon.level),
|
||||
x = x + 59,
|
||||
y = y + 17,
|
||||
shadow = true,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
@@ -288,7 +279,7 @@ class PasturePokemonScrollList(
|
||||
}
|
||||
|
||||
if (canUnpasture()) {
|
||||
if (isOwned() && canDefend() == true) {
|
||||
if (canDefend() == true) {
|
||||
conflictButton.setPos(x + 44, y + 3)
|
||||
conflictButton.render(context, mouseX, mouseY, partialTicks)
|
||||
}
|
||||
@@ -300,7 +291,7 @@ class PasturePokemonScrollList(
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, delta: Int): Boolean {
|
||||
if (canUnpasture()) {
|
||||
if (isOwned() && canDefend() == true && conflictButton.isHovered(mouseX, mouseY)) {
|
||||
if (canDefend() == true && conflictButton.isHovered(mouseX, mouseY)) {
|
||||
conflictButton.onPress()
|
||||
return true
|
||||
}
|
||||
@@ -312,4 +303,4 @@ class PasturePokemonScrollList(
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-225
@@ -1,225 +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.pasture
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.font
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.pc.StorageWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.gui.PCBoxWallpaperRepository
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.AdjustPastureRangePacket
|
||||
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.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
class PastureRangeWidget(x: Int, y: Int, private val configuration: PasturePCGUIConfiguration) :
|
||||
SoundlessWidget(x, y, StorageWidget.SCREEN_WIDTH, StorageWidget.SCREEN_HEIGHT, lang("ui.pasture.range")) {
|
||||
|
||||
private val rangeResource = cobblemonResource("textures/gui/pasture/pasture_range.png")
|
||||
private val glowResource = cobblemonResource("textures/gui/pc/wallpaper/basic/glow/wallpaper_basic_05.png")
|
||||
private val overlayResource = cobblemonResource("textures/gui/pc/pc_screen_overlay.png")
|
||||
private val infoResource = cobblemonResource("textures/gui/pasture/pasture_range_help.png")
|
||||
private val infoButtonResource = cobblemonResource("textures/gui/pasture/pasture_button.png")
|
||||
private val infoButtonSize = 17
|
||||
private val directions = listOf(configuration.facing, configuration.facing.clockWise, configuration.facing.opposite, configuration.facing.counterClockWise)
|
||||
private val arrowBounds = listOf(
|
||||
intArrayOf(75, 17, 103, 46), intArrayOf(116, 64, 152, 96),
|
||||
intArrayOf(75, 109, 103, 143), intArrayOf(26, 64, 62, 96)
|
||||
)
|
||||
// Centers of the numeral shadows in pasture_range.png, relative to its (85, 27) panel origin.
|
||||
private val numberPositions = listOf(89 to 37, 125 to 77, 89 to 114, 53 to 77)
|
||||
private var hoveredDirection: Direction? = null
|
||||
private var showInfo = false
|
||||
val isInfoOpen get() = showInfo
|
||||
fun closeInfo() { showInfo = false }
|
||||
|
||||
private val infoButtonX get() = x + 5
|
||||
private val infoButtonY get() = y + 5
|
||||
private val infoPanelX get() = x + 7
|
||||
private val infoPanelY get() = y + 40
|
||||
private val infoPanelWidth = 160
|
||||
private val infoPanelHeight = 74
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
blitk(
|
||||
matrixStack = context.pose(), texture = PCBoxWallpaperRepository.defaultWallpaper,
|
||||
x = x, y = y, width = width, height = height
|
||||
)
|
||||
blitk(
|
||||
matrixStack = context.pose(), texture = rangeResource,
|
||||
x = x + 3, y = y + 3, width = width - 6, height = height - 6,
|
||||
uOffset = 88, vOffset = 30, textureWidth = 349, textureHeight = 205
|
||||
)
|
||||
blitk(
|
||||
matrixStack = context.pose(), texture = glowResource,
|
||||
x = x - 17, y = y - 17, width = 208, height = 189
|
||||
)
|
||||
blitk(matrixStack = context.pose(), texture = overlayResource, x = x, y = y, width = width, height = height)
|
||||
hoveredDirection = if (showInfo) null else directionAt(mouseX.toDouble(), mouseY.toDouble())
|
||||
directions.indexOf(hoveredDirection).takeIf { it >= 0 }?.let { index ->
|
||||
renderArrowHighlight(context, index)
|
||||
}
|
||||
context.pose().pushPose()
|
||||
context.pose().translate(-0.5F, 0F, 0F)
|
||||
directions.forEachIndexed { index, direction ->
|
||||
val (numberX, numberY) = numberPositions[index]
|
||||
drawScaledText(context, text = Component.literal(configuration.range[direction].toString()),
|
||||
x = x + numberX + 1, y = y + numberY - 7, centered = true,
|
||||
colour = 0xFFFFFFFF.toInt())
|
||||
}
|
||||
context.pose().popPose()
|
||||
if (showInfo) context.fill(x + 3, y + 3, x + width - 3, y + height - 3, 0xAA002730.toInt())
|
||||
val infoHovered = isOverInfoButton(mouseX.toDouble(), mouseY.toDouble())
|
||||
// Use the same button face and persistent open-state highlight as the gear.
|
||||
blitk(matrixStack = context.pose(), texture = infoButtonResource,
|
||||
x = infoButtonX, y = infoButtonY, width = 13, height = infoButtonSize,
|
||||
textureWidth = 70, textureHeight = 34)
|
||||
blitk(matrixStack = context.pose(), texture = infoButtonResource,
|
||||
x = infoButtonX + 13, y = infoButtonY, width = 4, height = infoButtonSize,
|
||||
uOffset = 66, textureWidth = 70, textureHeight = 34)
|
||||
if (showInfo || infoHovered) context.fill(infoButtonX + 2, infoButtonY + 2,
|
||||
infoButtonX + 16, infoButtonY + 15, 0x88FFFFFF.toInt())
|
||||
blitk(matrixStack = context.pose(), texture = infoResource,
|
||||
x = infoButtonX + 4.5F, y = infoButtonY + 3.5F, width = 8, height = 10)
|
||||
if (showInfo) {
|
||||
val options = Minecraft.getInstance().options
|
||||
val boxX = infoPanelX
|
||||
val boxY = infoPanelY
|
||||
val boxWidth = infoPanelWidth
|
||||
val boxHeight = infoPanelHeight
|
||||
context.fill(boxX + 1, boxY, boxX + boxWidth - 1, boxY + boxHeight, 0x96FFFFFF.toInt())
|
||||
context.fill(boxX, boxY + 1, boxX + boxWidth, boxY + boxHeight - 1, 0x96FFFFFF.toInt())
|
||||
blitk(matrixStack = context.pose(), texture = PCBoxWallpaperRepository.defaultWallpaper,
|
||||
x = boxX + 1, y = boxY + 1, width = boxWidth - 2, height = boxHeight - 2,
|
||||
textureWidth = StorageWidget.SCREEN_WIDTH, textureHeight = StorageWidget.SCREEN_HEIGHT)
|
||||
val increaseBinding = if (options.keyAttack.matchesMouse(0)) lang("ui.pasture.range.left_click")
|
||||
else options.keyAttack.translatedKeyMessage.copy()
|
||||
val decreaseBinding = if (options.keyUse.matchesMouse(1)) lang("ui.pasture.range.right_click")
|
||||
else options.keyUse.translatedKeyMessage.copy()
|
||||
val columns = listOf(
|
||||
Triple(boxX + 43, lang("ui.pasture.range.increase").bold(), listOf(increaseBinding, lang("ui.pasture.range.scroll_up"))),
|
||||
Triple(boxX + 117, lang("ui.pasture.range.decrease").bold(), listOf(decreaseBinding, lang("ui.pasture.range.scroll_down")))
|
||||
)
|
||||
val detailWidth = columns.flatMap { it.third }.maxOf {
|
||||
Minecraft.getInstance().font.width(it.copy().font(CobblemonResources.DEFAULT_LARGE))
|
||||
}
|
||||
val detailScale = minOf(1F, 72F / detailWidth)
|
||||
drawScaledText(context, font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.pasture.range.help_title").bold(), x = boxX + 80, y = boxY + 8,
|
||||
centered = true, shadow = true)
|
||||
context.fill(boxX + 8, boxY + 22, boxX + boxWidth - 8, boxY + 23, 0x96FFFFFF.toInt())
|
||||
context.fill(boxX + 80, boxY + 27, boxX + 81, boxY + 66, 0x96FFFFFF.toInt())
|
||||
columns.forEach { (centerX, title, details) ->
|
||||
drawScaledText(context, font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = title, x = centerX, y = boxY + 29, centered = true, shadow = true)
|
||||
details.forEachIndexed { index, line ->
|
||||
drawScaledText(context, font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = line, x = centerX, y = boxY + 44 + index * 14,
|
||||
scale = detailScale, centered = true, shadow = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderArrowHighlight(context: GuiGraphics, index: Int) {
|
||||
fun fill(left: Int, top: Int, right: Int, bottom: Int) {
|
||||
context.fill(x + left, y + top, x + right, y + bottom, 0x66FFFFFF)
|
||||
}
|
||||
// Trace the arrow faces in pasture_range.png; horizontal arrows have longer stems.
|
||||
// Keep their offset drop shadows visible instead of brightening the surrounding background.
|
||||
when (index) {
|
||||
0 -> {
|
||||
for (row in 0..14) {
|
||||
val halfWidth = 3 + minOf(row, 11)
|
||||
fill(89 - halfWidth, 17 + row, 89 + halfWidth, 18 + row)
|
||||
}
|
||||
fill(81, 32, 97, 41)
|
||||
}
|
||||
1, 3 -> {
|
||||
for (row in 0..26) {
|
||||
val tip = 141 + minOf(row, 11, 26 - row)
|
||||
if (index == 1) fill(137, 64 + row, tip, 65 + row)
|
||||
else fill(178 - tip, 64 + row, 41, 65 + row)
|
||||
}
|
||||
if (index == 1) fill(116, 72, 137, 83)
|
||||
else fill(41, 72, 62, 83)
|
||||
}
|
||||
2 -> {
|
||||
fill(81, 109, 97, 123)
|
||||
for (row in 0..14) {
|
||||
val halfWidth = 14 - maxOf(0, row - 3)
|
||||
fill(89 - halfWidth, 123 + row, 89 + halfWidth, 124 + row)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun directionAt(mouseX: Double, mouseY: Double): Direction? {
|
||||
val index = arrowBounds.indexOfFirst { (left, top, right, bottom) ->
|
||||
mouseX >= x + left && mouseX < x + right &&
|
||||
mouseY >= y + top && mouseY < y + bottom
|
||||
}
|
||||
return directions.getOrNull(index)
|
||||
}
|
||||
|
||||
private fun adjust(direction: Direction, increase: Boolean): Boolean {
|
||||
AdjustPastureRangePacket(configuration.pastureId, direction, increase).sendToServer()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isOverInfoButton(mouseX: Double, mouseY: Double) =
|
||||
mouseX >= infoButtonX && mouseX < infoButtonX + infoButtonSize &&
|
||||
mouseY >= infoButtonY && mouseY < infoButtonY + infoButtonSize
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (pButton == 0 && isOverInfoButton(pMouseX, pMouseY)) {
|
||||
showInfo = !showInfo
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.PC_CLICK, 1F))
|
||||
return true
|
||||
}
|
||||
if (showInfo) {
|
||||
if (pMouseX < infoPanelX || pMouseX >= infoPanelX + infoPanelWidth ||
|
||||
pMouseY < infoPanelY || pMouseY >= infoPanelY + infoPanelHeight) closeInfo()
|
||||
return true
|
||||
}
|
||||
val direction = directionAt(pMouseX, pMouseY) ?: return false
|
||||
val options = Minecraft.getInstance().options
|
||||
return when {
|
||||
options.keyAttack.matchesMouse(pButton) -> adjust(direction, true)
|
||||
options.keyUse.matchesMouse(pButton) -> adjust(direction, false)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
|
||||
if (showInfo) return true
|
||||
val direction = directionAt(mouseX, mouseY) ?: return false
|
||||
if (scrollY == 0.0) return false
|
||||
return adjust(direction, scrollY > 0)
|
||||
}
|
||||
|
||||
override fun keyPressed(pKeyCode: Int, pScanCode: Int, pModifiers: Int): Boolean {
|
||||
if (showInfo) return !Minecraft.getInstance().options.keyInventory.matches(pKeyCode, pScanCode)
|
||||
val direction = hoveredDirection ?: return false
|
||||
val options = Minecraft.getInstance().options
|
||||
return when {
|
||||
options.keyAttack.matches(pKeyCode, pScanCode) -> adjust(direction, true)
|
||||
options.keyUse.matches(pKeyCode, pScanCode) -> adjust(direction, false)
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-31
@@ -20,9 +20,7 @@ import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonP
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.sounds.SoundManager
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.client.gui.components.Button
|
||||
|
||||
class PastureWidget(
|
||||
val storageWidget: StorageWidget,
|
||||
@@ -34,8 +32,6 @@ class PastureWidget(
|
||||
|
||||
companion object {
|
||||
private val baseResource = cobblemonResource("textures/gui/pasture/pasture_panel.png")
|
||||
private val buttonResource = cobblemonResource("textures/gui/pasture/pasture_button.png")
|
||||
private val gearResource = cobblemonResource("textures/gui/pasture/pasture_range_gear.png")
|
||||
}
|
||||
|
||||
private val recallButton = RecallButton(
|
||||
@@ -46,14 +42,6 @@ class PastureWidget(
|
||||
UnpastureAllPokemonPacket(pasturePCGUIConfiguration.pastureId).sendToServer()
|
||||
}
|
||||
|
||||
private val rangeButton = object : Button(x + 6, y + 174, 27, 17, lang("ui.pasture.range"), {
|
||||
storageWidget.pcGui.setPastureRangeEditing(!pasturePCGUIConfiguration.editingRange)
|
||||
}, DEFAULT_NARRATION) {
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
storageWidget.pcGui.playSound(CobblemonSounds.PC_CLICK)
|
||||
}
|
||||
}
|
||||
|
||||
val pastureScrollList = PasturePokemonScrollList(
|
||||
listX = x + 6,
|
||||
listY = y + 31,
|
||||
@@ -82,29 +70,11 @@ class PastureWidget(
|
||||
pastureScrollList.render(context, mouseX, mouseY, delta)
|
||||
|
||||
recallButton.render(context, mouseX, mouseY, delta)
|
||||
rangeButton.message = lang(if (pasturePCGUIConfiguration.editingRange) "ui.pasture.storage" else "ui.pasture.range")
|
||||
val buttonX = rangeButton.x
|
||||
val buttonY = rangeButton.y
|
||||
val highlighted = pasturePCGUIConfiguration.editingRange || rangeButton.isMouseOver(mouseX.toDouble(), mouseY.toDouble())
|
||||
blitk(matrixStack = context.pose(), texture = buttonResource, x = buttonX, y = buttonY,
|
||||
width = 23, height = 17, textureWidth = 70, textureHeight = 34)
|
||||
blitk(matrixStack = context.pose(), texture = buttonResource, x = buttonX + 23, y = buttonY,
|
||||
width = 4, height = 17, uOffset = 66, textureWidth = 70, textureHeight = 34)
|
||||
if (highlighted) context.fill(buttonX + 2, buttonY + 2, buttonX + 26, buttonY + 15, 0x88FFFFFF.toInt())
|
||||
val gearSize = 11
|
||||
val gearX = buttonX + (rangeButton.width - gearSize) / 2
|
||||
val gearY = buttonY + (rangeButton.height - gearSize) / 2
|
||||
if (highlighted) blitk(matrixStack = context.pose(), texture = gearResource,
|
||||
x = gearX + 1, y = gearY, width = gearSize, height = gearSize,
|
||||
red = 0.2F, green = 0.2F, blue = 0.2F)
|
||||
blitk(matrixStack = context.pose(), texture = gearResource,
|
||||
x = gearX, y = gearY, width = gearSize, height = gearSize)
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (rangeButton.mouseClicked(pMouseX, pMouseY, pButton)) return true
|
||||
if (recallButton.isHovered(pMouseX, pMouseY)) recallButton.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
if (pastureScrollList.isHovered(pMouseX, pMouseY)) pastureScrollList.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
return super.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
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.resources.sounds.SimpleSoundInstance
|
||||
@@ -64,6 +65,9 @@ class FilterWidget(
|
||||
|
||||
renderCursor(context, input)
|
||||
|
||||
if (iconHovered(mouseX, mouseY)) {
|
||||
context.renderTooltip(Minecraft.getInstance().font, lang("ui.pc.filter.tooltip"), mouseX, mouseY)
|
||||
}
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
@@ -77,4 +81,4 @@ class FilterWidget(
|
||||
|
||||
fun iconHovered(mouseX: Int, mouseY: Int): Boolean = mouseX >= (x - 9) && mouseY >= (y + 3)
|
||||
&& mouseX <= ((x - 9) + (ICON_SIZE * SCALE)) && mouseY <= ((y + 3) + (ICON_SIZE * SCALE))
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PasturePCGUIConfiguration
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary.Companion.iconCosmeticItemResource
|
||||
@@ -141,10 +140,7 @@ class PCGUI(
|
||||
// Add Exit Button
|
||||
this.addRenderableWidget(
|
||||
ExitButton(pX = x + 320, pY = y + 186) {
|
||||
if (storageWidget.editingPastureRange) {
|
||||
setPastureRangeEditing(false)
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
} else if (::wallpaperWidget.isInitialized && wallpaperWidget.visible) {
|
||||
if (::wallpaperWidget.isInitialized && wallpaperWidget.visible) {
|
||||
wallpaperWidget.visible = false
|
||||
configuration.showParty = true
|
||||
for (button in optionButtons) button.highlighted = false
|
||||
@@ -162,7 +158,7 @@ class PCGUI(
|
||||
pX = x + 220,
|
||||
pY = y + 16,
|
||||
forward = true
|
||||
) { if (!storageWidget.editingPastureRange) storageWidget.box += 1 }
|
||||
) { storageWidget.box += 1 }
|
||||
)
|
||||
|
||||
// Add Backwards Button
|
||||
@@ -171,7 +167,7 @@ class PCGUI(
|
||||
pX = x + 117,
|
||||
pY = y + 16,
|
||||
forward = false
|
||||
) { if (!storageWidget.editingPastureRange) storageWidget.box -= 1 }
|
||||
) { storageWidget.box -= 1 }
|
||||
)
|
||||
|
||||
// Add Filter Widget
|
||||
@@ -201,8 +197,6 @@ class PCGUI(
|
||||
storageWidget = storageWidget
|
||||
)
|
||||
this.addRenderableWidget(boxNameWidget)
|
||||
filterWidget.active = !storageWidget.editingPastureRange
|
||||
boxNameWidget.active = !storageWidget.editingPastureRange
|
||||
|
||||
// Initialise box options if not pasture
|
||||
if (storageWidget.pastureWidget == null) {
|
||||
@@ -697,10 +691,6 @@ class PCGUI(
|
||||
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
if (!storageWidget.editingPastureRange && filterWidget.iconHovered(mouseX, mouseY)) {
|
||||
context.renderTooltip(Minecraft.getInstance().font, lang("ui.pc.filter.tooltip"), mouseX, mouseY)
|
||||
}
|
||||
|
||||
// Item Tooltip
|
||||
if (pokemon != null) {
|
||||
val displayedItem = if (showCosmeticItem) pokemon.cosmeticItem else pokemon.heldItemNoCopy()
|
||||
@@ -721,34 +711,17 @@ class PCGUI(
|
||||
}
|
||||
}
|
||||
|
||||
fun setPastureRangeEditing(editing: Boolean) {
|
||||
val pasture = configuration as? PasturePCGUIConfiguration ?: return
|
||||
pasture.editingRange = editing
|
||||
if (!editing) storageWidget.pastureRangeWidget?.closeInfo()
|
||||
filterWidget.active = !editing
|
||||
boxNameWidget.active = !editing
|
||||
focused = null
|
||||
storageWidget.resetSelected()
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
val rangeWidget = storageWidget.pastureRangeWidget
|
||||
if (storageWidget.editingPastureRange && rangeWidget?.isInfoOpen == true &&
|
||||
children().none { it is ExitButton && it.isHovered(mouseX, mouseY) }) {
|
||||
return rangeWidget.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
// Trigger child component function as they will need to check the entire screen click area
|
||||
if (::boxNameWidget.isInitialized && !storageWidget.editingPastureRange) boxNameWidget.mouseClicked(mouseX, mouseY, button)
|
||||
if (::boxNameWidget.isInitialized) boxNameWidget.mouseClicked(mouseX, mouseY, button)
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
override fun mouseScrolled(mouseX: Double, mouseY: Double, amount: Double, verticalAmount: Double): Boolean {
|
||||
if (storageWidget.editingPastureRange &&
|
||||
storageWidget.pastureRangeWidget?.mouseScrolled(mouseX, mouseY, amount, verticalAmount) == true) return true
|
||||
storageWidget.pastureWidget?.let { pasture ->
|
||||
if (pasture.pastureScrollList.isHovered) pasture.pastureScrollList.mouseScrolled(mouseX, mouseY, amount, verticalAmount)
|
||||
}
|
||||
if (!storageWidget.editingPastureRange && storageWidget.isHovered && mouseX < (storageWidget.x + StorageWidget.SCREEN_WIDTH)) this.storageWidget.box -= verticalAmount.toInt()
|
||||
if (storageWidget.isHovered && mouseX < (storageWidget.x + StorageWidget.SCREEN_WIDTH)) this.storageWidget.box -= verticalAmount.toInt()
|
||||
if (::wallpaperWidget.isInitialized && wallpaperWidget.isHovered) wallpaperWidget.mouseScrolled(mouseX, mouseY, amount, verticalAmount)
|
||||
|
||||
val infoBoxX = ((width - BASE_WIDTH) / 2) + 9
|
||||
@@ -771,11 +744,6 @@ class PCGUI(
|
||||
}
|
||||
|
||||
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
||||
if (storageWidget.editingPastureRange) {
|
||||
if (keyCode != InputConstants.KEY_ESCAPE &&
|
||||
storageWidget.pastureRangeWidget?.keyPressed(keyCode, scanCode, modifiers) == true) return true
|
||||
if (keyCode == InputConstants.KEY_RIGHT || keyCode == InputConstants.KEY_LEFT) return true
|
||||
}
|
||||
val boxNameFocused = this::boxNameWidget.isInitialized && boxNameWidget.isFocused
|
||||
val filterFocused = this::filterWidget.isInitialized && filterWidget.isFocused
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PasturePCGUIConfiguration
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PastureWidget
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PastureRangeWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.gui.PCBoxWallpaperRepository
|
||||
@@ -75,9 +74,6 @@ class StorageWidget(
|
||||
private val releaseNoButton: ReleaseConfirmButton
|
||||
|
||||
var pastureWidget: PastureWidget? = null
|
||||
val pastureRangeWidget = (pcGui.configuration as? PasturePCGUIConfiguration)?.let { PastureRangeWidget(x, y, it) }
|
||||
val editingPastureRange: Boolean
|
||||
get() = (pcGui.configuration as? PasturePCGUIConfiguration)?.editingRange == true
|
||||
|
||||
var displayConfirmRelease = false
|
||||
var screenLoaded = false
|
||||
@@ -222,11 +218,6 @@ class StorageWidget(
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (editingPastureRange) {
|
||||
pastureRangeWidget?.render(context, mouseX, mouseY, delta)
|
||||
pastureWidget?.render(context, mouseX, mouseY, delta)
|
||||
return
|
||||
}
|
||||
val matrices = context.pose()
|
||||
// Party Label
|
||||
if (pcGui.configuration.showParty) {
|
||||
@@ -349,10 +340,6 @@ class StorageWidget(
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
if (editingPastureRange) {
|
||||
return pastureRangeWidget?.mouseClicked(pMouseX, pMouseY, pButton) == true ||
|
||||
pastureWidget?.mouseClicked(pMouseX, pMouseY, pButton) == true
|
||||
}
|
||||
if (displayConfirmRelease) {
|
||||
if (releaseYesButton.isHovered(pMouseX, pMouseY)) releaseYesButton.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
if (releaseNoButton.isHovered(pMouseX, pMouseY)) releaseNoButton.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
|
||||
@@ -28,9 +28,9 @@ import org.joml.Vector3f
|
||||
|
||||
open class PartySlot(
|
||||
x: Int, y: Int,
|
||||
private val pokemon: TradeStartedPacket.TradeablePokemon?,
|
||||
val pokemon: TradeStartedPacket.TradeablePokemon?,
|
||||
private val parent: TradeGUI,
|
||||
private val isOpposing: Boolean = false,
|
||||
val isOpposing: Boolean = false,
|
||||
onPress: OnPress
|
||||
) : Button(x, y, SIZE, SIZE, Component.literal("PartySlot"), onPress, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
val state = FloatingState()
|
||||
@@ -42,6 +42,8 @@ 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) {
|
||||
@@ -60,6 +62,17 @@ 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
|
||||
@@ -118,7 +131,16 @@ open class PartySlot(
|
||||
}
|
||||
|
||||
matrices.popPose()
|
||||
if (hasSelected()) {
|
||||
|
||||
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)
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = selectPointerResource,
|
||||
@@ -128,6 +150,7 @@ open class PartySlot(
|
||||
height = 8,
|
||||
scale = TradeGUI.SCALE
|
||||
)
|
||||
matrices.popPose()
|
||||
}
|
||||
|
||||
// Held Item
|
||||
@@ -145,8 +168,9 @@ open class PartySlot(
|
||||
}
|
||||
|
||||
open fun hasSelected(): Boolean {
|
||||
val offeredPokemon = if (isOpposing) parent.trade.oppositeOffer.get() else parent.trade.myOffer.get()
|
||||
return pokemon?.pokemonId == offeredPokemon?.uuid && pokemon != null
|
||||
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 }
|
||||
}
|
||||
|
||||
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,6 +25,7 @@ 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
|
||||
@@ -98,15 +99,23 @@ class TradeGUI(
|
||||
private val tradeAnimationArrowsResource = cobblemonResource("textures/gui/trade/trade_animation_arrows.png")
|
||||
}
|
||||
|
||||
private var offeredPokemonModel: ModelWidget? = null
|
||||
private var opposingOfferedPokemonModel: ModelWidget? = null
|
||||
private var offeredPokemonModels: MutableList<ModelWidget> = mutableListOf()
|
||||
private var opposingOfferedPokemonModels: MutableList<ModelWidget> = mutableListOf()
|
||||
|
||||
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
|
||||
@@ -125,30 +134,67 @@ class TradeGUI(
|
||||
}
|
||||
|
||||
trade.completedEmitter.subscribe {
|
||||
val (pokemonId1, pokemonId2) = it
|
||||
val myTradedPokemon = party.find { it?.pokemonId == pokemonId1 }
|
||||
val theirTradedPokemon = traderParty.find { it?.pokemonId == pokemonId2 }
|
||||
if (myTradedPokemon == null || theirTradedPokemon == null) {
|
||||
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()) {
|
||||
CobblemonNetwork.sendToServer(CancelTradePacket())
|
||||
return@subscribe onClose()
|
||||
}
|
||||
val tradedSlot = party.indexOf(myTradedPokemon)
|
||||
val opposingTradedSlot = traderParty.indexOf(theirTradedPokemon)
|
||||
party[tradedSlot] = theirTradedPokemon
|
||||
traderParty[opposingTradedSlot] = myTradedPokemon
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
trade.oppositeAcceptedMyOffer.set(false)
|
||||
CobblemonNetwork.sendToServer(UpdateTradeOfferPacket(Pair(theirTradedPokemon.pokemonId, PartyPosition(tradedSlot))))
|
||||
selectedPartyIndices.clear()
|
||||
selectedPartyIndices.addAll(newSelectedIndices)
|
||||
|
||||
val newOffers = selectedPartyIndices.mapNotNull { idx ->
|
||||
party[idx]?.let { it.pokemonId to PartyPosition(idx) }
|
||||
}
|
||||
CobblemonNetwork.sendToServer(UpdateTradeOfferPacket(newOffers))
|
||||
|
||||
rebuildWidgets()
|
||||
}
|
||||
|
||||
trade.oppositeOffer.subscribe { newOffer: Pokemon? ->
|
||||
setOfferedPokemon(pokemon = newOffer, isOpposing = true)
|
||||
trade.oppositeOffer.subscribe { newOffer: List<Pokemon> ->
|
||||
setOfferedPokemon(pokemonList = newOffer, isOpposing = true)
|
||||
}
|
||||
|
||||
trade.myOffer.subscribe { myOffer: Pokemon? ->
|
||||
setOfferedPokemon(pokemon = myOffer)
|
||||
trade.myOffer.subscribe { myOffer: List<Pokemon> ->
|
||||
setOfferedPokemon(pokemonList = myOffer)
|
||||
}
|
||||
|
||||
trade.oppositeAcceptedMyOffer.subscribe {
|
||||
@@ -216,9 +262,16 @@ class TradeGUI(
|
||||
pokemon = pokemon,
|
||||
parent = this,
|
||||
onPress = {
|
||||
if (!trade.acceptedOppositeOffer && !tradeProcessing) {
|
||||
val pk = if (offeredPokemon?.uuid == pokemon?.pokemonId) null else pokemon
|
||||
CobblemonNetwork.sendToServer(UpdateTradeOfferPacket(pk?.let { it.pokemonId to PartyPosition(partyIndex) }))
|
||||
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))
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
}
|
||||
@@ -250,8 +303,8 @@ class TradeGUI(
|
||||
).also { widget -> addRenderableWidget(widget) }
|
||||
}
|
||||
|
||||
setOfferedPokemon(pokemon = offeredPokemon, isOpposing = false)
|
||||
setOfferedPokemon(pokemon = opposingOfferedPokemon, isOpposing = true)
|
||||
setOfferedPokemon(pokemonList = offeredPokemons.toList(), isOpposing = false)
|
||||
setOfferedPokemon(pokemonList = opposingPokemons.toList(), isOpposing = true)
|
||||
|
||||
offeredPokemonMarkings = MarkingsWidget(x + 74.5, y + 21, offeredPokemon, false)
|
||||
opposingOfferedPokemonMarkings = MarkingsWidget(x + 177.5, y + 21, opposingOfferedPokemon, false)
|
||||
@@ -284,7 +337,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,
|
||||
@@ -313,20 +366,56 @@ 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)
|
||||
|
||||
opposingOfferedPokemonModel?.baseScale = scale
|
||||
opposingOfferedPokemonModel?.offsetY = scaleOffsetY
|
||||
opposingOfferedPokemonModel?.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()
|
||||
}
|
||||
|
||||
context.disableScissor()
|
||||
}
|
||||
|
||||
@@ -341,8 +430,46 @@ class TradeGUI(
|
||||
|
||||
renderInfoLabels(context, x, y)
|
||||
|
||||
renderPokemonInfo(offeredPokemon, false, context, x, y, mouseX, mouseY)
|
||||
renderPokemonInfo(opposingOfferedPokemon, true, context, x, y, mouseX, mouseY)
|
||||
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
|
||||
}
|
||||
|
||||
if (trade.acceptedOppositeOffer) {
|
||||
blitk(
|
||||
@@ -431,19 +558,25 @@ class TradeGUI(
|
||||
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
|
||||
// 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 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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,11 +613,13 @@ class TradeGUI(
|
||||
}
|
||||
|
||||
if (tradeAnimationProgress == (MAX_TRADE_PROGRESS + CRY_BUFFER)) {
|
||||
if (offeredPokemonModel !== null && opposingOfferedPokemonModel !== null) {
|
||||
offeredPokemonModel!!.state.activeAnimations.clear()
|
||||
offeredPokemonModel!!.state.addFirstAnimation(setOf("cry"))
|
||||
opposingOfferedPokemonModel!!.state.activeAnimations.clear()
|
||||
opposingOfferedPokemonModel!!.state.addFirstAnimation(setOf("cry"))
|
||||
offeredPokemonModels.forEach {
|
||||
it.state.activeAnimations.clear()
|
||||
it.state.addFirstAnimation(setOf("cry"))
|
||||
}
|
||||
opposingOfferedPokemonModels.forEach {
|
||||
it.state.activeAnimations.clear()
|
||||
it.state.addFirstAnimation(setOf("cry"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,41 +650,140 @@ class TradeGUI(
|
||||
|
||||
override fun renderMenuBackground(context: GuiGraphics) {}
|
||||
|
||||
private fun setOfferedPokemon(pokemon: Pokemon?, isOpposing: Boolean = false) {
|
||||
private fun setOfferedPokemon(pokemonList: List<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) {
|
||||
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
|
||||
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
|
||||
))
|
||||
}
|
||||
} else {
|
||||
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)
|
||||
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
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -557,10 +791,10 @@ class TradeGUI(
|
||||
}
|
||||
|
||||
private fun cancelTradeSound() {
|
||||
if (tradeSoundInstance !== null) Minecraft.getInstance().soundManager.stop(tradeSoundInstance)
|
||||
if (tradeSoundInstance != null) Minecraft.getInstance().soundManager.stop(tradeSoundInstance!!)
|
||||
}
|
||||
|
||||
private fun renderPokemonInfo(pokemon: Pokemon?, isOpposing: Boolean, context: GuiGraphics, x: Int, y: Int, mouseX: Int, mouseY: Int) {
|
||||
public fun renderPokemonInfo(pokemon: Pokemon?, isOpposing: Boolean, context: GuiGraphics, x: Int, y: Int, mouseX: Int, mouseY: Int) {
|
||||
if (pokemon != null) {
|
||||
val matrices = context.pose()
|
||||
// Level
|
||||
@@ -1047,4 +1281,4 @@ class TradeGUI(
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.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()
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
-2
@@ -23,8 +23,6 @@ object OpenPastureHandler : ClientNetworkPacketHandler<OpenPasturePacket> {
|
||||
pastureId = packet.pastureId,
|
||||
limit = packet.limit,
|
||||
permissions = packet.permissions,
|
||||
range = packet.range,
|
||||
facing = packet.facing,
|
||||
pasturedPokemon = SettableObservable(packet.tetheredPokemon)
|
||||
)
|
||||
|
||||
|
||||
-26
@@ -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.client.net.pasture
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.gui.pasture.PasturePCGUIConfiguration
|
||||
import com.cobblemon.mod.common.client.gui.pc.PCGUI
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureRangePacket
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
|
||||
object UpdatePastureRangeHandler : ClientNetworkPacketHandler<UpdatePastureRangePacket> {
|
||||
override fun handle(packet: UpdatePastureRangePacket, client: Minecraft) {
|
||||
val configuration = (client.screen as? PCGUI)?.configuration as? PasturePCGUIConfiguration ?: return
|
||||
if (configuration.pastureId != packet.pastureId) return
|
||||
configuration.range = packet.range
|
||||
client.soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.PC_CLICK, 1F))
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +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.pasture
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.gui.pc.PCGUI
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureRecoveryPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
object UpdatePastureRecoveryHandler : ClientNetworkPacketHandler<UpdatePastureRecoveryPacket> {
|
||||
override fun handle(packet: UpdatePastureRecoveryPacket, client: Minecraft) {
|
||||
val slots = (client.screen as? PCGUI)?.storage?.pastureWidget?.pastureScrollList?.children() ?: return
|
||||
slots.firstOrNull { it.pokemon.pokemonId == packet.pokemonId }?.pokemon?.apply {
|
||||
healingAfterFaint = packet.fainted
|
||||
respawnAt = packet.respawnAt
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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()?.uuid == packet.pokemonId) {
|
||||
if (CobblemonClient.trade?.myOffer?.get()?.any { it.uuid == packet.pokemonId } == true) {
|
||||
CobblemonClient.trade!!.oppositeAcceptedMyOffer.set(packet.accepted)
|
||||
} else if (CobblemonClient.trade?.oppositeOffer?.get()?.uuid == packet.pokemonId) {
|
||||
} else if (CobblemonClient.trade?.oppositeOffer?.get()?.any { it.uuid == packet.pokemonId } == true) {
|
||||
CobblemonClient.trade!!.acceptedOppositeOffer = packet.accepted
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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.pokemonId1 to packet.pokemonId2)
|
||||
trade.completedEmitter.emit(packet.pokemonIds1 to packet.pokemonIds2)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ import net.minecraft.client.Minecraft
|
||||
|
||||
object TradeStartedHandler : ClientNetworkPacketHandler<TradeStartedPacket> {
|
||||
override fun handle(packet: TradeStartedPacket, client: Minecraft) {
|
||||
Cobblemon.LOGGER.error("handle trade start from: " + packet.traderId)
|
||||
Cobblemon.LOGGER.info("Trade started with {}", packet.traderId)
|
||||
val trade = ClientTrade()
|
||||
CobblemonClient.trade = trade
|
||||
Minecraft.getInstance().setScreen(
|
||||
|
||||
+2
-2
@@ -18,9 +18,9 @@ object TradeUpdatedHandler : ClientNetworkPacketHandler<TradeUpdatedPacket> {
|
||||
val trade = CobblemonClient.trade ?: return
|
||||
|
||||
if (packet.playerId == Minecraft.getInstance().player?.uuid) {
|
||||
trade.myOffer.set(packet.pokemon)
|
||||
trade.myOffer.set(packet.pokemons)
|
||||
} else {
|
||||
trade.oppositeOffer.set(packet.pokemon)
|
||||
trade.oppositeOffer.set(packet.pokemons)
|
||||
}
|
||||
trade.oppositeAcceptedMyOffer.set(false)
|
||||
trade.acceptedOppositeOffer = false
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.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<Pokemon?>(null)
|
||||
var oppositeOffer = SettableObservable<Pokemon?>(null)
|
||||
var myOffer = SettableObservable<List<Pokemon>>(emptyList())
|
||||
var oppositeOffer = SettableObservable<List<Pokemon>>(emptyList())
|
||||
var tradeProcessing = SettableObservable(Pair(false, false))
|
||||
var oppositeAcceptedMyOffer = SettableObservable(false)
|
||||
var acceptedOppositeOffer = false
|
||||
|
||||
var completedEmitter = SimpleObservable<Pair<UUID, UUID>>()
|
||||
var completedEmitter = SimpleObservable<Pair<List<UUID>, List<UUID>>>()
|
||||
var cancelEmitter = SimpleObservable<Unit>()
|
||||
}
|
||||
@@ -11,6 +11,7 @@ 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
|
||||
@@ -120,6 +121,7 @@ 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 {
|
||||
|
||||
-1
@@ -160,5 +160,4 @@ class CobblemonChestBoatEntity(entityType: EntityType<CobblemonChestBoatEntity>,
|
||||
private const val INVENTORY_SLOTS = 27
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -166,6 +166,7 @@ import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LightLayer
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.level.block.SuspiciousEffectHolder
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
@@ -303,7 +304,6 @@ open class PokemonEntity(
|
||||
var drops: DropTable? = null
|
||||
|
||||
var tethering: PokemonPastureBlockEntity.Tethering? = null
|
||||
private var nextPastureReturnAttempt = 0
|
||||
|
||||
// TODO review if we still want this
|
||||
var queuedToDespawn = false
|
||||
@@ -738,29 +738,34 @@ open class PokemonEntity(
|
||||
|
||||
// Check to see if the entity needs recalled or repositioned if pastured.
|
||||
fun checkPastureTether() {
|
||||
val currentTethering = tethering ?: return
|
||||
val world = level() as? ServerLevel ?: return
|
||||
if (ticksLived == 1 && world.hasChunkAt(currentTethering.pasturePos)) {
|
||||
val pasture = world.getBlockEntity(currentTethering.pasturePos) as? PokemonPastureBlockEntity
|
||||
pasture?.tetheredPokemon?.find { it.tetheringId == currentTethering.tetheringId }?.let { tethering = it }
|
||||
}
|
||||
if (tethering!!.canRoamTo(x, z) || !world.hasChunkAt(currentTethering.pasturePos)) return
|
||||
navigation.stop()
|
||||
(moveControl as? PokemonMoveControl)?.apply { stop(); stopBanking() }
|
||||
brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
deltaMovement = Vec3.ZERO
|
||||
if (ticksLived < nextPastureReturnAttempt) return
|
||||
val pasture = world.getBlockEntity(currentTethering.pasturePos) as? PokemonPastureBlockEntity
|
||||
val position = pasture?.findSpawnPosition(this, blockPosition())
|
||||
if (position != null) {
|
||||
teleportTo(position.x, position.y, position.z)
|
||||
nextPastureReturnAttempt = 0
|
||||
} else if (pasture == null) {
|
||||
tethering = null
|
||||
pokemon.recall()
|
||||
return
|
||||
} else {
|
||||
nextPastureReturnAttempt = ticksLived + 20
|
||||
// Teleport a pastured mon back to the pasture block if they are out of range
|
||||
if (this.tethering != null && !this.tethering!!.box.contains(this.x, this.y, this.z)) {
|
||||
|
||||
// Gather the ideal position (behind the pastureBlock)
|
||||
val pastureBlockPos = this.tethering!!.pasturePos
|
||||
val state = this.level().getBlockState(pastureBlockPos)
|
||||
|
||||
// Check to ensure we are working with a pastureblock here and it hasn't been broken
|
||||
if (state.block == CobblemonBlocks.PASTURE) {
|
||||
val direction = state.getValue(HorizontalDirectionalBlock.FACING)
|
||||
val width = this.boundingBox.xsize
|
||||
val tpPos = pastureBlockPos.offset(direction.normal.multiply(ceil(width).toInt() + 1)).center
|
||||
val heightAllowance = 4.0 // Allow spawning up to x blocks above the pastureBlock y level
|
||||
|
||||
// Attempt tp and recall if it fails
|
||||
if (!this.randomTeleport(tpPos.x, tpPos.y + heightAllowance, tpPos.z, false)) {
|
||||
// If the teleport was not successful then recall the mon
|
||||
this.tethering = null
|
||||
this.pokemon.recall()
|
||||
} else {
|
||||
// Stop any now invalid navigation post teleport
|
||||
this.navigation.stop()
|
||||
}
|
||||
} else {
|
||||
// If the block is destroyed or something else went wrong.
|
||||
this.tethering = null
|
||||
this.pokemon.recall()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1795,7 +1800,7 @@ open class PokemonEntity(
|
||||
removalObservable.emit(reason)
|
||||
this.brain.clearMemories()
|
||||
|
||||
if (reason.shouldDestroy() && pokemon.tetheringId != null && tethering == null) {
|
||||
if (reason.shouldDestroy() && pokemon.tetheringId != null) {
|
||||
pokemon.tetheringId = null
|
||||
}
|
||||
if (evolutionEntity != null) {
|
||||
@@ -2739,4 +2744,9 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
fun hasRider() = this.passengers.any { it is LivingEntity }
|
||||
}
|
||||
|
||||
override fun playStepSound(pos: BlockPos, state: BlockState) {
|
||||
if (this.pokemon.species.silenceStepSounds) return
|
||||
super.playStepSound(pos, state)
|
||||
}
|
||||
}
|
||||
+2
-20
@@ -29,7 +29,6 @@ import net.minecraft.tags.FluidTags
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes
|
||||
import net.minecraft.world.entity.ai.control.MoveControl
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.phys.AABB
|
||||
@@ -107,14 +106,7 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
|
||||
|
||||
if (banking) {
|
||||
pokemonEntity.yRot += bankRightDegreesPerTick
|
||||
val forward = bankForwardBlocksPerTick * mediumSpeed
|
||||
val tethering = pokemonEntity.tethering
|
||||
if (tethering?.canRoamTo(
|
||||
pokemonEntity.x - Mth.sin(pokemonEntity.yRot.toRadians()) * forward,
|
||||
pokemonEntity.z + Mth.cos(pokemonEntity.yRot.toRadians()) * forward
|
||||
) != false) {
|
||||
pokemonEntity.travel(Vec3(0.0, bankUpwardsBlocksPerTick.toDouble(), bankForwardBlocksPerTick.toDouble()).scale(mediumSpeed.toDouble()))
|
||||
}
|
||||
pokemonEntity.travel(Vec3(0.0, bankUpwardsBlocksPerTick.toDouble(), bankForwardBlocksPerTick.toDouble()).scale(mediumSpeed.toDouble()))
|
||||
if (bankDurationTicks > 0) {
|
||||
bankDurationTicks--
|
||||
}
|
||||
@@ -288,16 +280,6 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
|
||||
}
|
||||
}
|
||||
}
|
||||
val tethering = pokemonEntity.tethering
|
||||
val motion = mob.deltaMovement
|
||||
if (tethering?.canRoamTo(mob.x, mob.z) == true &&
|
||||
!tethering.canRoamTo(mob.x + motion.x, mob.z + motion.z)) {
|
||||
mob.navigation.stop()
|
||||
pokemonEntity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
stop()
|
||||
stopBanking()
|
||||
mob.deltaMovement = Vec3(0.0, motion.y, 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -387,4 +369,4 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
|
||||
strafeForwards = 0.0f
|
||||
strafeRight = 0.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ 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
|
||||
@@ -164,26 +165,21 @@ object AdvancementHandler : EventHandler {
|
||||
}
|
||||
|
||||
fun onTradeCompleted(event : TradeEvent.Post) {
|
||||
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)
|
||||
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 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.getOwnerPlayer()?.awardStat(getStat(Cobblemon.statistics.TRADED))
|
||||
event.tradeParticipant2Pokemon.getOwnerPlayer()?.awardStat(getStat(Cobblemon.statistics.TRADED))
|
||||
event.tradeParticipant1Pokemon.firstOrNull()?.getOwnerPlayer()?.awardStat(getStat(Cobblemon.statistics.TRADED))
|
||||
event.tradeParticipant2Pokemon.firstOrNull()?.getOwnerPlayer()?.awardStat(getStat(Cobblemon.statistics.TRADED))
|
||||
}
|
||||
|
||||
fun onFossilRevived(event : FossilRevivedEvent) {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* 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))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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,6 +945,8 @@ 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,6 +9,7 @@
|
||||
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
|
||||
@@ -23,10 +24,15 @@ import net.minecraft.world.level.Level
|
||||
class PonigiriItem : Item(
|
||||
Properties().stacksTo(64)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(2)
|
||||
.saturationModifier(0.55f)
|
||||
.nutrition(NUTRITION)
|
||||
.saturationModifier(SATURATION_MODIFIER)
|
||||
.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)
|
||||
@@ -59,4 +65,9 @@ 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
|
||||
}
|
||||
}
|
||||
+13
-16
@@ -6,26 +6,23 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pasture
|
||||
package com.cobblemon.mod.common.net.messages.client.bag
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.pasture.PastureRange
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import java.util.UUID
|
||||
|
||||
class UpdatePastureRangePacket(val pastureId: UUID, val range: PastureRange) : NetworkPacket<UpdatePastureRangePacket> {
|
||||
override val id = ID
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(pastureId)
|
||||
range.encode(buffer)
|
||||
}
|
||||
|
||||
class UpdateBagMenuDataPacket(val categoryId: Int, val scroll: Int): NetworkPacket<UpdateBagMenuDataPacket> {
|
||||
companion object {
|
||||
val ID = cobblemonResource("update_pasture_range")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = UpdatePastureRangePacket(
|
||||
buffer.readUUID(), PastureRange.decode(buffer)
|
||||
)
|
||||
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)
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.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)
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.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 })
|
||||
}
|
||||
}
|
||||
+4
-16
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.net.messages.client.pasture
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.pasture.PasturePermissions
|
||||
import com.cobblemon.mod.common.api.pasture.PastureRange
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.net.IntSize
|
||||
@@ -20,7 +19,6 @@ import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.core.Direction
|
||||
|
||||
/**
|
||||
* Opens a pasture GUI using the provided data.
|
||||
@@ -30,7 +28,7 @@ import net.minecraft.core.Direction
|
||||
* @author Hiroku
|
||||
* @since April 9th, 2023
|
||||
*/
|
||||
class OpenPasturePacket(val pcId: UUID, val pastureId: UUID, val limit: Int, val tetheredPokemon: List<PasturePokemonDataDTO>, val permissions: PasturePermissions, val range: PastureRange, val facing: Direction) : NetworkPacket<OpenPasturePacket> {
|
||||
class OpenPasturePacket(val pcId: UUID, val pastureId: UUID, val limit: Int, val tetheredPokemon: List<PasturePokemonDataDTO>, val permissions: PasturePermissions) : NetworkPacket<OpenPasturePacket> {
|
||||
class PasturePokemonDataDTO(
|
||||
val pokemonId: UUID,
|
||||
val playerId: UUID,
|
||||
@@ -41,9 +39,7 @@ class OpenPasturePacket(val pcId: UUID, val pastureId: UUID, val limit: Int, val
|
||||
val heldItem: ItemStack,
|
||||
val level: Int,
|
||||
val entityKnown: Boolean,
|
||||
var behaviourFlags: Set<PokemonBehaviourFlag> = emptySet(),
|
||||
var healingAfterFaint: Boolean = false,
|
||||
var respawnAt: Long = 0L
|
||||
var behaviourFlags: Set<PokemonBehaviourFlag> = emptySet()
|
||||
) {
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): PasturePokemonDataDTO {
|
||||
@@ -57,8 +53,6 @@ class OpenPasturePacket(val pcId: UUID, val pastureId: UUID, val limit: Int, val
|
||||
val level = buffer.readSizedInt(IntSize.U_SHORT)
|
||||
val entityKnown = buffer.readBoolean()
|
||||
val behaviourFlags = buffer.readList { it.readEnumConstant(PokemonBehaviourFlag::class.java) }.toSet()
|
||||
val healingAfterFaint = buffer.readBoolean()
|
||||
val respawnAt = buffer.readLong()
|
||||
|
||||
return PasturePokemonDataDTO(
|
||||
pokemonId = pokemonId,
|
||||
@@ -70,9 +64,7 @@ class OpenPasturePacket(val pcId: UUID, val pastureId: UUID, val limit: Int, val
|
||||
heldItem = heldItem,
|
||||
level = level,
|
||||
entityKnown = entityKnown,
|
||||
behaviourFlags = behaviourFlags,
|
||||
healingAfterFaint = healingAfterFaint,
|
||||
respawnAt = respawnAt
|
||||
behaviourFlags = behaviourFlags
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -88,8 +80,6 @@ class OpenPasturePacket(val pcId: UUID, val pastureId: UUID, val limit: Int, val
|
||||
buffer.writeSizedInt(IntSize.U_SHORT, level)
|
||||
buffer.writeBoolean(entityKnown)
|
||||
buffer.writeCollection(behaviourFlags) { _, flag -> buffer.writeEnumConstant(flag) }
|
||||
buffer.writeBoolean(healingAfterFaint)
|
||||
buffer.writeLong(respawnAt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +95,7 @@ class OpenPasturePacket(val pcId: UUID, val pastureId: UUID, val limit: Int, val
|
||||
dtos.add(PasturePokemonDataDTO.decode(buffer))
|
||||
}
|
||||
val permissions = PasturePermissions.decode(buffer)
|
||||
return OpenPasturePacket(pcId, pastureId, limit, dtos, permissions, PastureRange.decode(buffer), buffer.readEnum(Direction::class.java))
|
||||
return OpenPasturePacket(pcId, pastureId, limit, dtos, permissions)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +110,5 @@ class OpenPasturePacket(val pcId: UUID, val pastureId: UUID, val limit: Int, val
|
||||
tethered.encode(buffer)
|
||||
}
|
||||
permissions.encode(buffer)
|
||||
range.encode(buffer)
|
||||
buffer.writeEnum(facing)
|
||||
}
|
||||
}
|
||||
-29
@@ -1,29 +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.pasture
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import java.util.UUID
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
data class UpdatePastureRecoveryPacket(val pokemonId: UUID, val fainted: Boolean, val respawnAt: Long) : NetworkPacket<UpdatePastureRecoveryPacket> {
|
||||
override val id = ID
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("update_pasture_recovery")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = UpdatePastureRecoveryPacket(buffer.readUUID(), buffer.readBoolean(), buffer.readLong())
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(pokemonId)
|
||||
buffer.writeBoolean(fainted)
|
||||
buffer.writeLong(respawnAt)
|
||||
}
|
||||
}
|
||||
+7
-4
@@ -23,16 +23,19 @@ import java.util.UUID
|
||||
* @author Hiroku
|
||||
* @since March 5th, 2023
|
||||
*/
|
||||
class TradeCompletedPacket(val pokemonId1: UUID, val pokemonId2: UUID) : NetworkPacket<TradeCompletedPacket> {
|
||||
class TradeCompletedPacket(val pokemonIds1: List<UUID>, val pokemonIds2: List<UUID>) : NetworkPacket<TradeCompletedPacket> {
|
||||
companion object {
|
||||
val ID = cobblemonResource("trade_completed")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = TradeCompletedPacket(buffer.readUUID(), buffer.readUUID())
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = TradeCompletedPacket(
|
||||
buffer.readList { it.readUUID() },
|
||||
buffer.readList { it.readUUID() }
|
||||
)
|
||||
}
|
||||
|
||||
override val id = ID
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(pokemonId1)
|
||||
buffer.writeUUID(pokemonId2)
|
||||
buffer.writeCollection(pokemonIds1) { buf, id -> buf.writeUUID(id) }
|
||||
buffer.writeCollection(pokemonIds2) { buf, id -> buf.writeUUID(id) }
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -12,10 +12,6 @@ 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
|
||||
|
||||
@@ -27,15 +23,18 @@ import java.util.UUID
|
||||
* @author Hiroku
|
||||
* @since March 5th, 2023
|
||||
*/
|
||||
class TradeUpdatedPacket(val playerId: UUID, val pokemon: Pokemon?) : NetworkPacket<TradeUpdatedPacket>, UnsplittablePacket {
|
||||
class TradeUpdatedPacket(val playerId: UUID, val pokemons: List<Pokemon>) : NetworkPacket<TradeUpdatedPacket>, UnsplittablePacket {
|
||||
companion object {
|
||||
val ID = cobblemonResource("trade_updated")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = TradeUpdatedPacket(buffer.readUUID(), buffer.readNullable { Pokemon.S2C_CODEC.decode(buffer) })
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = TradeUpdatedPacket(
|
||||
buffer.readUUID(),
|
||||
buffer.readList { Pokemon.S2C_CODEC.decode(it as RegistryFriendlyByteBuf) }
|
||||
)
|
||||
}
|
||||
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(playerId)
|
||||
buffer.writeNullable(pokemon) { _, pokemon -> Pokemon.S2C_CODEC.encode(buffer, pokemon) }
|
||||
buffer.writeCollection(pokemons) { buf, pokemon -> Pokemon.S2C_CODEC.encode(buf as RegistryFriendlyByteBuf, pokemon) }
|
||||
}
|
||||
}
|
||||
-32
@@ -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.server.pasture
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import java.util.UUID
|
||||
|
||||
class AdjustPastureRangePacket(val pastureId: UUID, val direction: Direction, val increase: Boolean) : NetworkPacket<AdjustPastureRangePacket> {
|
||||
override val id = ID
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(pastureId)
|
||||
buffer.writeEnum(direction)
|
||||
buffer.writeBoolean(increase)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("adjust_pasture_range")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = AdjustPastureRangePacket(
|
||||
buffer.readUUID(), buffer.readEnum(Direction::class.java), buffer.readBoolean()
|
||||
)
|
||||
}
|
||||
}
|
||||
+9
-5
@@ -11,26 +11,30 @@ 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 newOffer: Pair<UUID, PartyPosition>?): NetworkPacket<UpdateTradeOfferPacket> {
|
||||
class UpdateTradeOfferPacket(val newOffers: List<Pair<UUID, PartyPosition>>): NetworkPacket<UpdateTradeOfferPacket> {
|
||||
companion object {
|
||||
val ID = cobblemonResource("update_trade_offer")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = UpdateTradeOfferPacket(buffer.readNullable { buffer.readUUID() to buffer.readPartyPosition() })
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = UpdateTradeOfferPacket(
|
||||
buffer.readList { it.readUUID() to it.readPartyPosition() }
|
||||
)
|
||||
}
|
||||
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeNullable(newOffer) { buffer, (pokemonId, partyPosition) ->
|
||||
buffer.writeUUID(pokemonId)
|
||||
buffer.writePartyPosition(partyPosition)
|
||||
buffer.writeCollection(newOffers) { buf, (pokemonId, partyPosition) ->
|
||||
buf.writeUUID(pokemonId)
|
||||
buf.writePartyPosition(partyPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +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.serverhandling.pasture
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.pasture.PastureLinkManager
|
||||
import com.cobblemon.mod.common.api.pasture.PastureRange
|
||||
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureRangePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.AdjustPastureRangePacket
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object AdjustPastureRangeHandler : ServerNetworkPacketHandler<AdjustPastureRangePacket> {
|
||||
override fun handle(packet: AdjustPastureRangePacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
val link = PastureLinkManager.getLinkByPlayer(player) ?: return
|
||||
if (link.linkId != packet.pastureId || packet.direction.axis == Direction.Axis.Y) return
|
||||
val pasture = player.serverLevel().getBlockEntity(link.pos) as? PokemonPastureBlockEntity ?: return
|
||||
val range = pasture.getRange().adjusted(packet.direction, if (packet.increase) 1 else -1)
|
||||
if (!range.isValid(PastureRange.MAX_DISTANCE)) {
|
||||
UpdatePastureRangePacket(link.linkId, pasture.getRange()).sendToPlayer(player)
|
||||
return
|
||||
}
|
||||
pasture.setRange(range)
|
||||
for (viewer in player.serverLevel().players()) {
|
||||
val viewerLink = PastureLinkManager.getLinkByPlayer(viewer) ?: continue
|
||||
if (viewerLink.pos == link.pos && viewerLink.dimension == link.dimension) {
|
||||
UpdatePastureRangePacket(viewerLink.linkId, range).sendToPlayer(viewer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-7
@@ -9,18 +9,24 @@
|
||||
package com.cobblemon.mod.common.net.serverhandling.pasture
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.pasture.PastureLinkManager
|
||||
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.SetPastureConflictPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
|
||||
|
||||
object SetPastureConflictHandler : ServerNetworkPacketHandler<SetPastureConflictPacket> {
|
||||
override fun handle(packet: SetPastureConflictPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
val link = PastureLinkManager.getLinkByPlayer(player) ?: return
|
||||
val pasture = player.level().getBlockEntity(link.pos) as? PokemonPastureBlockEntity ?: return
|
||||
val tethering = pasture.tetheredPokemon.firstOrNull { it.pokemonId == packet.pokemonId && it.playerId == player.uuid } ?: return
|
||||
pasture.setConflict(tethering, packet.enabled)
|
||||
val world = player.level()
|
||||
val entity = world.getEntitiesOfClass(PokemonEntity::class.java, player.boundingBox.inflate(64.0))
|
||||
.firstOrNull { it.pokemon.uuid == packet.pokemonId }
|
||||
?: return
|
||||
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.PASTURE_CONFLICT, packet.enabled)
|
||||
entity.remakeBrain()
|
||||
|
||||
// Send packet from the server to client GUI to update the toggle button
|
||||
UpdatePastureConflictFlagPacket(packet.pokemonId, packet.enabled).sendToPlayer(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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?.uuid == packet.pokemonOfferId) {
|
||||
if (trade.getOpposingOffer(tradeParticipant).pokemon.any { it.uuid == packet.pokemonOfferId }) {
|
||||
trade.updateAcceptance(tradeParticipant, packet.newAcceptance)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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?.uuid == packet.pokemonOfferId) {
|
||||
if (trade.getOpposingOffer(tradeParticipant).pokemon.any { it.uuid == packet.pokemonOfferId }) {
|
||||
trade.performTrade(tradeParticipant)
|
||||
}
|
||||
}
|
||||
|
||||
+9
-12
@@ -12,6 +12,7 @@ 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
|
||||
@@ -21,20 +22,16 @@ 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 newOffer = packet.newOffer
|
||||
if (newOffer == null) {
|
||||
trade.updateOffer(tradeParticipant, null)
|
||||
} else {
|
||||
val (pokemonId, partyPosition) = newOffer
|
||||
val party = player.party()
|
||||
val newOffers = packet.newOffers
|
||||
|
||||
val validPokemons = mutableListOf<Pokemon>()
|
||||
val party = player.party()
|
||||
for ((pokemonId, partyPosition) in newOffers) {
|
||||
val pokemon = party[partyPosition]
|
||||
if (pokemon == null || pokemon.uuid != pokemonId) {
|
||||
return
|
||||
} else if (!pokemon.tradeable) {
|
||||
return
|
||||
} else {
|
||||
trade.updateOffer(tradeParticipant, pokemon)
|
||||
if (pokemon != null && pokemon.uuid == pokemonId && pokemon.tradeable) {
|
||||
validPokemons.add(pokemon)
|
||||
}
|
||||
}
|
||||
trade.updateOffer(tradeParticipant, validPokemons)
|
||||
}
|
||||
}
|
||||
@@ -173,6 +173,7 @@ class Species : ShowdownIdentifiable {
|
||||
.addStandardFunctions()
|
||||
.addSpeciesFunctions(this)
|
||||
|
||||
var silenceStepSounds = false
|
||||
|
||||
fun initialize() {
|
||||
Cobblemon.statProvider.provide(this)
|
||||
@@ -256,6 +257,7 @@ class Species : ShowdownIdentifiable {
|
||||
}
|
||||
|
||||
this.riding.encode(buffer)
|
||||
buffer.writeBoolean(this.silenceStepSounds)
|
||||
}
|
||||
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -299,6 +301,7 @@ class Species : ShowdownIdentifiable {
|
||||
}
|
||||
}
|
||||
this.riding = RidingProperties.decode(buffer)
|
||||
this.silenceStepSounds = buffer.readBoolean()
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
|
||||
@@ -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: Pokemon?) {
|
||||
fun updateOffer(tradeParticipant: TradeParticipant, pokemon: List<Pokemon>) {
|
||||
getOffer(tradeParticipant).updateOffer(pokemon)
|
||||
getOffer(getOppositePlayer(tradeParticipant)).accepted = false
|
||||
player1.updateOffer(this, tradeParticipant, pokemon)
|
||||
@@ -30,8 +30,9 @@ class ActiveTrade(val player1: TradeParticipant, val player2: TradeParticipant)
|
||||
val offer = getOpposingOffer(tradeParticipant)
|
||||
if (offer.accepted != acceptance) {
|
||||
offer.accepted = acceptance
|
||||
getOppositePlayer(tradeParticipant).changeTradeAcceptance(this, offer.pokemon!!.uuid, acceptance)
|
||||
tradeParticipant.changeTradeAcceptance(this, offer.pokemon!!.uuid, acceptance)
|
||||
val firstId = offer.pokemon.firstOrNull()?.uuid ?: java.util.UUID.randomUUID()
|
||||
getOppositePlayer(tradeParticipant).changeTradeAcceptance(this, firstId, acceptance)
|
||||
tradeParticipant.changeTradeAcceptance(this, firstId, acceptance)
|
||||
}
|
||||
|
||||
if (offer.accepted && getOffer(tradeParticipant).accepted) {
|
||||
@@ -51,8 +52,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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -64,12 +65,14 @@ class ActiveTrade(val player1: TradeParticipant, val player2: TradeParticipant)
|
||||
}
|
||||
|
||||
fun completeTrade() {
|
||||
player1.completeTrade(this, player1Offer.pokemon!!.uuid, player2Offer.pokemon!!.uuid)
|
||||
player2.completeTrade(this, player2Offer.pokemon!!.uuid, player1Offer.pokemon!!.uuid)
|
||||
val uuids1 = player1Offer.pokemon.map { it.uuid }
|
||||
val uuids2 = player2Offer.pokemon.map { it.uuid }
|
||||
player1.completeTrade(this, uuids1, uuids2)
|
||||
player2.completeTrade(this, uuids2, uuids1)
|
||||
|
||||
player1Offer.pokemon = null
|
||||
player1Offer.pokemon = emptyList()
|
||||
player1Offer.accepted = false
|
||||
player2Offer.pokemon = null
|
||||
player2Offer.pokemon = emptyList()
|
||||
player2Offer.accepted = false
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ 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
|
||||
@@ -101,71 +102,98 @@ object TradeManager : RequestManager<TradeManager.TradeRequest>() {
|
||||
fun performTrade(
|
||||
activeTrade: ActiveTrade,
|
||||
player1: TradeParticipant,
|
||||
pokemon1: Pokemon,
|
||||
pokemon1: List<Pokemon>,
|
||||
player2: TradeParticipant,
|
||||
pokemon2: Pokemon
|
||||
pokemon2: List<Pokemon>
|
||||
) {
|
||||
val party1 = player1.party
|
||||
val party2 = player2.party
|
||||
|
||||
if (pokemon1 !in party1 || pokemon2 !in party2) {
|
||||
if (pokemon1.any { it !in party1 } || pokemon2.any { it !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
|
||||
}
|
||||
|
||||
CobblemonEvents.TRADE_EVENT_PRE.postThen(TradeEvent.Pre(player1, pokemon2, player2, pokemon1)) {
|
||||
val party1 = player1.party
|
||||
val party2 = player2.party
|
||||
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
|
||||
}
|
||||
|
||||
val player1Removed = party1.remove(pokemon1)
|
||||
val player2Removed = party2.remove(pokemon2)
|
||||
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) }
|
||||
|
||||
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.")
|
||||
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 (!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.")
|
||||
(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.")
|
||||
}
|
||||
|
||||
// Revert any changes if one of the removals failed
|
||||
if (player1Removed) party1.add(pokemon1)
|
||||
if (player2Removed) party2.add(pokemon2)
|
||||
player1Removed.forEach { party1.add(it) }
|
||||
player2Removed.forEach { party2.add(it) }
|
||||
return@postThen
|
||||
}
|
||||
|
||||
// If player1 is the OT, keep track of the friendship
|
||||
pokemon1.cacheFriendship(player1.uuid)
|
||||
pokemon1.forEach { it.cacheFriendship(player1.uuid) }
|
||||
// If player2 is the OT, keep track of the friendship
|
||||
pokemon2.cacheFriendship(player2.uuid)
|
||||
pokemon2.forEach { it.cacheFriendship(player2.uuid) }
|
||||
|
||||
// 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 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 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)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
party2.add(pokemon1)
|
||||
party1.add(pokemon2)
|
||||
pokemon1.forEach { party2.add(it) }
|
||||
pokemon2.forEach { party1.add(it) }
|
||||
|
||||
pokemon1.lockedEvolutions.filterIsInstance<TradeEvolution>().firstOrNull {
|
||||
it.attemptEvolution(pokemon1, 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) }
|
||||
|
||||
pokemon2.lockedEvolutions.filterIsInstance<TradeEvolution>().firstOrNull {
|
||||
it.attemptEvolution(pokemon2, pokemon1)
|
||||
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++
|
||||
}
|
||||
}
|
||||
}
|
||||
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: Pokemon? = null
|
||||
var pokemon: List<Pokemon> = emptyList()
|
||||
var accepted = false
|
||||
|
||||
fun updateOffer(pokemon: Pokemon?) {
|
||||
fun updateOffer(pokemon: List<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: Pokemon?)
|
||||
fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: List<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, pokemonId1: UUID, pokemonId2: UUID)
|
||||
fun completeTrade(trade: ActiveTrade, pokemonIds1: List<UUID>, pokemonIds2: List<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: Pokemon?) {
|
||||
override fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: List<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, pokemonId1: UUID, pokemonId2: UUID) {
|
||||
player.sendPacket(TradeCompletedPacket(pokemonId1, pokemonId2))
|
||||
override fun completeTrade(trade: ActiveTrade, pokemonIds1: List<UUID>, pokemonIds2: List<UUID>) {
|
||||
player.sendPacket(TradeCompletedPacket(pokemonIds1, pokemonIds2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ class DummyTradeParticipant(val pokemonList: MutableList<Pokemon>) : TradePartic
|
||||
// Don't need to do any notifying.
|
||||
}
|
||||
|
||||
override fun completeTrade(trade: ActiveTrade, pokemonId1: UUID, pokemonId2: UUID) {
|
||||
override fun completeTrade(trade: ActiveTrade, pokemonIds1: List<UUID>, pokemonIds2: List<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: Pokemon?) {
|
||||
override fun updateOffer(trade: ActiveTrade, tradeParticipant: TradeParticipant, pokemon: List<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 1..depth) {
|
||||
val bellowBlockPos = blockPosition().below(currentDepth)
|
||||
for (currentDepth in 0..depth) {
|
||||
val bellowBlockPos = blockPosBelowThatAffectsMyMovement.below(currentDepth)
|
||||
val blockState = level().getBlockState(bellowBlockPos)
|
||||
|
||||
if (blockState.isAir || !blockState.isCollisionShapeFullBlock(level(), bellowBlockPos)) continue
|
||||
if (blockState.isAir) continue
|
||||
|
||||
val elementOrTags = ExtraCodecs.TAG_OR_ELEMENT_ID.listOf().decode(JavaOps.INSTANCE, blocks.toList()).result().get().first
|
||||
elementOrTags.forEach {
|
||||
|
||||
@@ -27,5 +27,9 @@ 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))
|
||||
}
|
||||
+12
@@ -1815,6 +1815,12 @@
|
||||
"wings_open": {
|
||||
"scale": 0
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
|
||||
"0.5": "q.run_molang('cobblemon:stepsound_claw_medium');",
|
||||
"1.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
|
||||
"1.5": "q.run_molang('cobblemon:stepsound_claw_medium');"
|
||||
}
|
||||
},
|
||||
"animation.pidgeot.mount_ground_idle": {
|
||||
@@ -3631,6 +3637,12 @@
|
||||
"wings_open": {
|
||||
"scale": 0
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
|
||||
"0.5": "q.run_molang('cobblemon:stepsound_claw_medium');",
|
||||
"1.0": "q.run_molang('cobblemon:stepsound_claw_medium');",
|
||||
"1.5": "q.run_molang('cobblemon:stepsound_claw_medium');"
|
||||
}
|
||||
},
|
||||
"animation.pidgeot.ride_ground_walk": {
|
||||
|
||||
+308
-74
@@ -1682,6 +1682,12 @@
|
||||
"1.3333": [10, 9, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"0.4583": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"0.6667": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"1.125": "q.run_molang('cobblemon:stepsound_standard_medium');"
|
||||
}
|
||||
},
|
||||
"animation.arcanine.ride_ground_walk": {
|
||||
@@ -2639,6 +2645,12 @@
|
||||
"chest_fluff_right": {
|
||||
"rotation": [5, "-22.5+math.cos(q.anim_time*90*8-120)*15", "-math.sin(q.anim_time*90*8-120)*3"]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.125": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"0.2083": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"0.2917": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"0.375": "q.run_molang('cobblemon:stepsound_standard_medium');"
|
||||
}
|
||||
},
|
||||
"animation.arcanine.ride_ground_run": {
|
||||
@@ -4161,41 +4173,101 @@
|
||||
"eye_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
|
||||
"0.5": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
|
||||
"1.6667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, 0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [-0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, 0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [-0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eye_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
|
||||
"0.5": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
|
||||
"1.6667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, 0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, 0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"0.5": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"1.6667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"0.5": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"1.6667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
@@ -4823,41 +4895,101 @@
|
||||
"eye_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
|
||||
"0.5": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, 0.1]},
|
||||
"1.6667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, 0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [-0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, 0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [-0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eye_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
|
||||
"0.5": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, 0.1]},
|
||||
"1.6667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, 0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, 0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"0.5": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"1.6667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"0.5": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"1.6667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
@@ -5287,14 +5419,20 @@
|
||||
"position": {
|
||||
"0.0": [-0.1, 0, 0.1],
|
||||
"0.125": [-0.1, 0, 0.1],
|
||||
"0.1667": {"pre": [-0.1, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [-0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eye_right": {
|
||||
"position": {
|
||||
"0.0": [0.1, 0, 0.1],
|
||||
"0.125": [0.1, 0, 0.1],
|
||||
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5491,47 +5629,95 @@
|
||||
"eye_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
|
||||
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.2, 0, 0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [-0.2, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eye_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
|
||||
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.2, 0, 0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [0.2, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
|
||||
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.2, 0, 0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [-0.2, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
|
||||
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.2, 0, 0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [0.2, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left_hurt": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"0.3333": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_right_hurt": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"0.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
@@ -6238,47 +6424,95 @@
|
||||
"eye_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
|
||||
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.2, 0, 0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [-0.2, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eye_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
|
||||
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.2, 0, 0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [0.2, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.2, 0, 0.1]},
|
||||
"0.3333": {"pre": [-0.2, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.2, 0, 0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [-0.2, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.2, 0, 0.1]},
|
||||
"0.3333": {"pre": [0.2, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.2, 0, 0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [0.2, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left_hurt": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"0.3333": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_right_hurt": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"0.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
|
||||
+8
@@ -3150,6 +3150,10 @@
|
||||
"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": {
|
||||
@@ -4473,6 +4477,10 @@
|
||||
"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": {
|
||||
|
||||
+56
-10
@@ -566,6 +566,12 @@
|
||||
"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": {
|
||||
@@ -780,15 +786,27 @@
|
||||
"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": {
|
||||
@@ -1186,18 +1204,36 @@
|
||||
"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": {
|
||||
@@ -2204,6 +2240,16 @@
|
||||
"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,6 +800,8 @@
|
||||
"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",
|
||||
@@ -1198,7 +1200,14 @@
|
||||
"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",
|
||||
@@ -1307,18 +1316,6 @@
|
||||
"cobblemon.ui.sort.discovered": "Sort by discovered status",
|
||||
"cobblemon.ui.pasture": "Pasture",
|
||||
"cobblemon.ui.pasture.recall_all": "Recall All",
|
||||
"cobblemon.ui.pasture.range": "Range",
|
||||
"cobblemon.ui.pasture.storage": "PC",
|
||||
"cobblemon.ui.pasture.fainted": "Fainted",
|
||||
"cobblemon.ui.pasture.returning": "Returning",
|
||||
"cobblemon.ui.pasture.ready": "Waiting",
|
||||
"cobblemon.ui.pasture.range.left_click": "Left click",
|
||||
"cobblemon.ui.pasture.range.right_click": "Right click",
|
||||
"cobblemon.ui.pasture.range.help_title": "Range controls",
|
||||
"cobblemon.ui.pasture.range.increase": "Increase",
|
||||
"cobblemon.ui.pasture.range.decrease": "Decrease",
|
||||
"cobblemon.ui.pasture.range.scroll_up": "Scroll up",
|
||||
"cobblemon.ui.pasture.range.scroll_down": "Scroll down",
|
||||
"cobblemon.pasture.too_many_nearby": "There are too many Pokémon nearby.",
|
||||
"cobblemon.ui.interact.give.item": "Change held item",
|
||||
"cobblemon.ui.interact.give.cosmetic_item": "Change cosmetic item",
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
{
|
||||
"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]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"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]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"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]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"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]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"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,6 +261,24 @@
|
||||
"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 } ]
|
||||
},
|
||||
@@ -2031,6 +2049,850 @@
|
||||
{ "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": [
|
||||
{
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Loaded 100 of 622 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user