Compare commits

..
Author SHA1 Message Date
ewwww 34fc434883 implemented new battle animations for happiny 2026-06-27 05:51:30 -04:00
ewwww 74949a02de yungoos poser tweak 2026-06-27 05:51:04 -04:00
ewwww 1617c1b087 added zubat physical animation 2026-06-27 04:57:03 -04:00
ewwww 4b1c180538 added poliwrath walk animation 2026-06-27 04:56:50 -04:00
ewwww cba6f51706 implemented new yungoos & gumshoos animations 2026-06-27 03:46:00 -04:00
ewwww 9b9fbedaf7 Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-06-26 19:27:45 -04:00
ewwww 8c3acd9a0e 'angery' typo 2026-06-26 18:23:48 -04:00
CaptainLennie 4ab52cac0e Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-06-26 19:28:24 +02:00
CaptainLennie 68805a5dd1 Fixed tentacool using ground animations while swimming on the surface (and updated to JSON poser) 2026-06-26 19:28:10 +02:00
Jerzykv 5a0b4e8f99 Alolan Vulpix portrait tweak 2026-06-26 14:03:11 +02:00
Jerzykv 3e9d3a307f Implemented animations for Rellor and Rabsca 2026-06-26 13:59:14 +02:00
ewwww 7c4d3ecb71 tweaked aerodactyl's walkspeed 2026-06-26 07:30:01 -04:00
ewwww e91fd5596a implemented new vulpix animations 2026-06-26 07:29:29 -04:00
ewwww f9d218adf8 forgot something 2026-06-25 05:46:04 -04:00
ewwww 05d70b28e7 monitor screen updates 2026-06-25 05:41:30 -04:00
ewwww 6755462eb0 added new animations for noctowl 2026-06-25 05:39:58 -04:00
ewwww 7ef3facac8 added new animations for drowzee and hypno 2026-06-25 04:07:39 -04:00
ewwww b7c16324bd misc texture fixes 2026-06-24 04:05:06 -04:00
ewwww e1cc9c7aba added new animations for Togetic 2026-06-22 02:45:55 -04:00
ewwww 79e821a438 added new animations for Staryu and Starmie 2026-06-22 01:08:45 -04:00
ewwww 19dd57feed form name corrections 2026-06-20 13:16:12 -04:00
ewwww e739b57a08 grammar. 2026-06-20 01:22:04 -04:00
ewwww 2044762b72 various poser alterations that accidentally got reverted 2026-06-17 05:33:34 -04:00
ewwww 77117e83c7 implemented (non-riding) animations & corrected scales for Duraludon & Archaludon 2026-06-17 05:33:21 -04:00
Carmendar 55f4e6e738 Goodra ride anim adjustments 2026-06-17 00:57:18 -05:00
ewwww 10d9d97c11 restored broken or missing seat locators for Ariados, Bastiodon, Dhelmise, Dondozo, Drifblim, Girafarig, and Klinklang 2026-06-15 00:06:56 -04:00
RedGenesectNinja 69a75ffcd4 Fixed broken Alola bias Exeggcute textures 2026-06-13 13:25:57 -05:00
RedGenesectNinja a3c5a6c377 Implemented Yamask fixes 2026-06-09 21:58:33 -05:00
ewwww b7e27fa52a Merge remote-tracking branch 'origin/implement_pokemon' into implement_pokemon 2026-06-05 21:10:08 -04:00
ewwww dc87ffd2a8 luvdisc faint fix 2026-06-05 21:09:49 -04:00
199 changed files with 73267 additions and 8473 deletions

No files matched your search

+23 -7
View File
@@ -59,13 +59,13 @@
- Ice type Pokémon are now immune to Packed Snow
### New rideable Pokémon
- Drampa
- Archeops
- Skarmory
- Crobat
- Goodra
- Hisuian Goodra
- Skarmory
- Milotic
- Archeops
- Goodra
- Goodra (Hisuian Form)
- Drampa
### Pokémon Added
#### Generation 3
@@ -171,6 +171,14 @@
- Changed models for every existing regional bias
### Animation updates for the following Pokémon
- Happiny
- Poliwrath
- Zubat
- Vulpix
- Drowzee
- Hypno
- Noctowl
- Skarmory
- Skitty
- Flygon
@@ -202,8 +210,16 @@
- Yamask
- Cofagrigus
- Luvdisc
- Staryu
- Starmie
- Togetic
- Rellor
- Rabsca
- Yungoos
- Gumshoos
#### Added sounds to the following moves
- Absorb
- Aurora Beam
- Double Team
@@ -232,10 +248,12 @@
### Fixes
- Adjusted Croagunk's walkspeed
- Adjusted Aerodactyl's walkspeed
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly
- Fixed Litleo not blinking
- Fixed Garchomp T-posing when sleeping while out of battle.
- Fixed Omanyte and Omastar incorrectly using water animations on land.
- Sharp Beak can now be crafted
- Metal Alloy can now be crafted
- Ability Capsules can now be brewed
@@ -300,7 +318,6 @@
- Regional Foods will now prioritize being eaten instead of used for healing Pokémon, shift clicking will use it as healing
- Resolved Z-Fighting on Pokédex Models
- Restored Ninjask's ability to do barrel rolls
- Fixed a crash caused by adding enchanted items to the Resurrection Machine
### Fixes
- Fixed Croagunk's walkspeed
@@ -361,7 +378,6 @@
- Separated all the functions of MoLangFunctions.kt into their own files.
- Spawn buckets and their base weights are now provided by the spawner, with different base weights for world, fishing, snack, and habitat spawn buckets.
- Removed "SpawnBucket" class in favour of just storing maps of bucket names to weights.
- Fixed nicknames not being applied to Pokémon spawned from `spawn_pool_world` files
### Molang & Datapacks
- Added `moveset_builders` datapack folder for different styles of movesets.
@@ -10,14 +10,16 @@ package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.mixin.accessor.SinglePoolElementAccessor;
import com.cobblemon.mod.common.world.structureprocessors.HeightRangeStructureProcessor;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.pools.*;
import net.minecraft.world.level.levelgen.structure.pools.alias.PoolAliasLookup;
import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings;
import net.minecraft.world.level.levelgen.structure.pools.JigsawPlacement;
import net.minecraft.world.level.levelgen.structure.pools.LegacySinglePoolElement;
import net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement;
import net.minecraft.world.level.levelgen.structure.pools.StructurePoolElement;
import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
import org.spongepowered.asm.mixin.Mixin;
@@ -26,38 +28,24 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Optional;
@Mixin(JigsawPlacement.class)
public class JigsawPlacementMixin {
@Inject(
method = "addPieces(Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;Lnet/minecraft/core/Holder;Ljava/util/Optional;ILnet/minecraft/core/BlockPos;ZLjava/util/Optional;ILnet/minecraft/world/level/levelgen/structure/pools/alias/PoolAliasLookup;Lnet/minecraft/world/level/levelgen/structure/pools/DimensionPadding;Lnet/minecraft/world/level/levelgen/structure/templatesystem/LiquidSettings;)Ljava/util/Optional;",
at = @At("RETURN"),
method = "addPieces*",
at = @At("HEAD"),
cancellable = true
)
private static void onAddPieces(
Structure.GenerationContext context,
Holder<StructureTemplatePool> startPool,
Optional<ResourceLocation> startJigsawName,
int maxDepth,
BlockPos pos,
boolean useExpansionHack,
Optional<Heightmap.Types> projectStartToHeightmap,
int maxDistanceFromCenter,
PoolAliasLookup aliasLookup,
DimensionPadding dimensionPadding,
LiquidSettings liquidSettings,
CallbackInfoReturnable<Optional<Structure.GenerationStub>> cir
private static void cobblemon$cancelInvalidHeightRangeStart(
CallbackInfoReturnable<Optional<Structure.GenerationStub>> cir,
@Local(argsOnly = true, ordinal = 0) Structure.GenerationContext generationContext,
@Local(argsOnly = true, ordinal = 0) Holder<StructureTemplatePool> startPool,
@Local(argsOnly = true, ordinal = 0) BlockPos startPos
) {
Optional<Structure.GenerationStub> result = cir.getReturnValue();
if (result.isEmpty()) {
return;
}
BlockPos spawnPos = result.get().position();
boolean canPlace = cobblemon$canAnyStartElementPlace(context, startPool, spawnPos);
if (canPlace) {
if (cobblemon$canAnyStartElementPlace(generationContext, startPool, startPos)) {
return;
}
@@ -70,22 +58,19 @@ public class JigsawPlacementMixin {
Holder<StructureTemplatePool> startPool,
BlockPos startPos
) {
for (StructurePoolElement element : startPool.value().templates) {
List<StructurePoolElement> elements = startPool.value().getShuffledTemplates(RandomSource.create(0L));
for (StructurePoolElement element : elements) {
Optional<HeightRangeStructureProcessor> heightRangeProcessor = cobblemon$getHeightRangeProcessor(element);
if (heightRangeProcessor.isEmpty()) {
return true;
}
HeightRangeStructureProcessor processor = heightRangeProcessor.get();
boolean valid = processor.isValidPlacement(
if (heightRangeProcessor.get().isValidPlacement(
generationContext.chunkGenerator(),
generationContext.heightAccessor(),
generationContext.randomState(),
startPos
);
if (valid) {
)) {
return true;
}
}
@@ -108,4 +93,5 @@ public class JigsawPlacementMixin {
return Optional.empty();
}
}
}
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelGuiFactoryKt;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.client.keybind.keybinds.RidingFreelookBinding;
import com.cobblemon.mod.common.duck.RidePassenger;
@@ -68,39 +67,6 @@ public abstract class MouseHandlerMixin {
@Unique private double cobblemon$timeDelta;
@Inject(
method = "onPress",
at = @At("HEAD"),
cancellable = true
)
public void cobblemon$pokeskillGuiControl(long windowPointer, int button, int action, int modifiers, CallbackInfo ci) {
if (button == 0 && action == 1) {
// Make sure no menus are open already
if (this.minecraft.screen == null && this.minecraft.getOverlay() == null) {
// Check to see if party key is held
if (PartySendBinding.INSTANCE.getWasDown()) {
// Don't want to send out a pokemon if we let go of the key
PartySendBinding.INSTANCE.actioned();
//Open the actual gui
var player = Minecraft.getInstance().player;
var storage = CobblemonClient.INSTANCE.getStorage();
var selectedPokemon = storage.getParty().get(storage.getSelectedSlot());
if (selectedPokemon != null && player != null) {
//canApplyChange = false
var gui = InteractWheelGuiFactoryKt.createPokeSkillGui(player, selectedPokemon);
Minecraft.getInstance().setScreen(gui);
}
// Stop the rest of minecraft click logic like punching and using items
ci.cancel();
}
}
}
}
@Inject(
method = "onScroll",
at = @At(
@@ -308,9 +308,7 @@ object Cobblemon {
this.config.maxPokemonLevel,
this.config.maxPokemonFriendship,
this.config.maxDynamaxLevel,
this.config.unlockAllMoveDexMovesByDefault,
this.config.pokemonIntrinsicSizeMin,
this.config.pokemonIntrinsicSizeMax
this.config.unlockAllMoveDexMovesByDefault
).sendToPlayer(player)
}
@@ -24,13 +24,26 @@ import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
import com.cobblemon.mod.common.client.net.effect.*
import com.cobblemon.mod.common.client.net.gui.*
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.SetActiveTMPacketHandler
import com.cobblemon.mod.common.client.net.gui.SetTMMachineContainerDataPacketHandler
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
import com.cobblemon.mod.common.client.net.habitat.OpenHabitatBlockEditorHandler
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
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.*
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.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.pokedex.ServerConfirmedRegisterHandler
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundSeatAssignmentPacketHandler
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
@@ -49,7 +62,14 @@ import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
import com.cobblemon.mod.common.client.net.storage.pc.*
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.*
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.net.PacketRegisterInfo
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
@@ -65,13 +85,21 @@ import com.cobblemon.mod.common.net.messages.client.data.*
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
import com.cobblemon.mod.common.net.messages.client.effect.*
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.net.messages.client.effect.SaccharineLogBlockParticlesPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.net.messages.client.habitat.OpenHabitatBlockEditorPacket
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
import com.cobblemon.mod.common.net.messages.client.pasture.*
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.PokemonUnpasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
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
@@ -92,17 +120,45 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.RenamePCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.*
import com.cobblemon.mod.common.net.messages.client.ui.*
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.*
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SetActiveTMPacket
import com.cobblemon.mod.common.net.messages.client.ui.SetTMMachineContainerDataPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
@@ -129,7 +185,11 @@ import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPack
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.*
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
@@ -142,12 +202,21 @@ import com.cobblemon.mod.common.net.messages.server.storage.party.PartyTutorialP
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
import com.cobblemon.mod.common.net.messages.server.trade.*
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.UsePokeSkillHandler
import com.cobblemon.mod.common.net.serverhandling.battle.*
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
import com.cobblemon.mod.common.net.serverhandling.behaviour.DamageOnCollisionPacketHandler
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
@@ -175,7 +244,11 @@ import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandl
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.*
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdatePassengerPositionHandler
@@ -191,7 +264,12 @@ import com.cobblemon.mod.common.net.serverhandling.storage.party.PartyTutorialPa
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
import com.cobblemon.mod.common.net.serverhandling.trade.*
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerPlayer
@@ -261,7 +339,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RideBoostsUpdatePacket.ID, RideBoostsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RideStaminaUpdatePacket.ID, RideStaminaUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(SkillCooldownsUpdatePacket.ID, SkillCooldownsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(AlphaUpdatePacket.ID, AlphaUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(ScaleModifierUpdatePacket.ID, ScaleModifierUpdatePacket::decode, PokemonUpdatePacketHandler()))
@@ -362,8 +439,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
list.add(PacketRegisterInfo(PokeSkillsRegistrySyncPacket.ID, PokeSkillsRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -455,7 +530,6 @@ object CobblemonNetwork {
// Interaction Packets
list.add(PacketRegisterInfo(InteractPokemonPacket.ID, InteractPokemonPacket::decode, InteractPokemonHandler))
list.add(PacketRegisterInfo(RequestPlayerInteractionsPacket.ID, RequestPlayerInteractionsPacket::decode, RequestInteractionsHandler))
list.add(PacketRegisterInfo(UsePokeSkillPacket.ID, UsePokeSkillPacket::decode, UsePokeSkillHandler))
// Storage Packets
list.add(PacketRegisterInfo(SendOutPokemonPacket.ID, SendOutPokemonPacket::decode, SendOutPokemonHandler))
@@ -1,68 +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
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.entity.pokemon.PokeSkill
import com.cobblemon.mod.common.net.messages.client.data.PokeSkillsRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.adapters.ActionEffectTimelineAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.TextAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.entity.player.Player
/**
* The JSON data registry for all the possible [PokeSkill]s.
*
* @author Hiroku
* @since August 31st, 2025
*/
object CobblemonPokeSkills : JsonDataRegistry<PokeSkill> {
override val id = cobblemonResource("poke_skills")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<CobblemonPokeSkills>()
override val typeToken = TypeToken.get(PokeSkill::class.java)
override val resourcePath = "poke_skills"
override val gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(ActionEffectTimeline::class.java, ActionEffectTimelineAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(Component::class.java, TextAdapter)
.create()
var skills = mapOf<ResourceLocation, PokeSkill>()
fun getAccessibleSkills(player: Player, pokemon: Pokemon): List<PokeSkill> {
return skills.values.filter { it.canAccess(player, pokemon) }
}
override fun reload(data: Map<ResourceLocation, PokeSkill>) {
data.forEach { (id, skill) -> skill.id = id }
skills = data
observable.emit(this)
Cobblemon.LOGGER.info("Loaded ${skills.size} PokéSkills")
}
override fun sync(player: ServerPlayer) {
player.sendPacket(PokeSkillsRegistrySyncPacket(skills.values.toList()))
}
}
@@ -293,11 +293,11 @@ object MoLangFunctions {
)
value.functions["is_in"] = Function put@{ params: MoParams ->
val tag = TagKey.create(key, ResourceLocation.parse(params.getString(0).replace("#", "")))
return@put DoubleValue(value.obj.`is`(tag))
return@put DoubleValue(if (value.obj.`is`(tag)) 1.0 else 0.0)
}
value.functions["is_of"] = Function put@{ params: MoParams ->
val identifier = ResourceLocation.parse(params.getString(0))
return@put DoubleValue(value.obj.`is`(identifier))
return@put DoubleValue(if (value.obj.`is`(identifier)) 1.0 else 0.0)
}
return value
}
@@ -25,7 +25,7 @@ object DropEntryMoLangFunctions : AbstractMoLangFunctionHolder<DropEntry>() {
map["max_selectable_times"] = { DoubleValue(drop.maxSelectableTimes.toDouble()) }
map["can_drop"] = { params ->
val pokemon = params.getOrNull<ObjectValue<Pokemon>>(0)?.obj
DoubleValue(drop.canDrop(pokemon))
DoubleValue(if (drop.canDrop(pokemon)) 1.0 else 0.0)
}
return map
}
@@ -35,14 +35,12 @@ import com.cobblemon.mod.common.util.effectiveName
import com.cobblemon.mod.common.util.getBlockStatesWithPos
import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
import com.cobblemon.mod.common.util.getIntOrNull
import com.cobblemon.mod.common.util.getIsSubmerged
import com.cobblemon.mod.common.util.getOrNull
import com.cobblemon.mod.common.util.getStringOrNull
import com.cobblemon.mod.common.util.isStandingOn
import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.worldRegistry
import net.minecraft.core.BlockPos
import net.minecraft.core.registries.Registries
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
@@ -50,10 +48,7 @@ import net.minecraft.tags.TagKey
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.damagesource.DamageTypes
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.level.block.BonemealableBlock
import net.minecraft.world.level.block.CropBlock
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import java.util.UUID
@@ -83,13 +78,8 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
"vertical_velocity" to { DoubleValue(thisEntity.deltaMovement.y) },
"is_on_ground" to { _ -> DoubleValue(thisEntity.onGround()) },
"world" to { _ -> thisEntity.level().worldRegistry.wrapAsHolder(thisEntity.level()).asWorldMoLangValue() },
"dimension" to { StringValue(thisEntity.level().dimension().location().toString()) },
"biome" to { _ -> thisEntity.level().getBiome(thisEntity.blockPosition()).asBiomeMoLangValue() },
"is_passenger" to { DoubleValue(thisEntity.isPassenger) },
"is_passenger" to isPassenger@{ params ->
val passengerEntity = (params.get<MoValue>(0) as? ObjectValue<*>)?.obj as? LivingEntity ?: return@isPassenger DoubleValue.ZERO
DoubleValue(passengerEntity in thisEntity.passengers)
},
"discard" to { thisEntity.discard() },
"is_sneaking" to { _ -> DoubleValue(thisEntity.isShiftKeyDown) },
"is_sprinting" to { _ -> DoubleValue(thisEntity.isSprinting) },
@@ -131,62 +121,6 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
listOf(thisEntity.deltaMovement.x, thisEntity.deltaMovement.y, thisEntity.deltaMovement.z)
.asArrayValue(::DoubleValue)
},
"set_position" to { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
thisEntity.setPos(x, y, z)
DoubleValue.ONE
},
"fertilize_nearby_crops" to { params -> //TODO: pretty bespoke. Maybe should be moved or generalized?
val radius = params.getIntOrNull(0) ?: 8
val maxCrops = params.getIntOrNull(1) ?: 8
var fertilizedCount = 0
val level = thisEntity.level()
val centerPos = thisEntity.blockPosition()
// Find all bonemealable blocks within radius
val bonemealableBlocks = mutableListOf<BlockPos>()
for (x in -radius..radius) {
for (y in -3..3) { // Limited vertical range
for (z in -radius..radius) {
val pos = centerPos.offset(x, y, z)
val blockState = level.getBlockState(pos)
val block = blockState.block
// Check if block can be bonemealed
if (block is BonemealableBlock && block is CropBlock && block.isValidBonemealTarget(level, pos, blockState)) {
bonemealableBlocks.add(pos)
}
}
}
}
// Shuffle and take up to maxCrops blocks to fertilize
bonemealableBlocks.shuffle()
val blocksToFertilize = bonemealableBlocks.take(maxCrops)
for (pos in blocksToFertilize) {
val blockState = level.getBlockState(pos)
val block = blockState.block
if (block is BonemealableBlock && block.isValidBonemealTarget(level, pos, blockState)) {
if (block.isBonemealSuccess(level, level.random, pos, blockState)) {
block.performBonemeal(level as ServerLevel, level.random, pos, blockState)
// Add bonemeal particle
val particlePos = block.getParticlePos(pos)
level.levelEvent(1505, particlePos, 15) // Same event used for bonemealing in vanilla
fertilizedCount++
}
}
}
DoubleValue(fertilizedCount.toDouble())
},
"tags" to {
val tags = thisEntity.tags
val array = ArrayStruct(hashMapOf())
@@ -299,7 +233,7 @@ object EntityMoLangFunctions : AbstractMoLangFunctionHolder<Entity>() {
val intangible = params.getBooleanOrNull(0) ?: true
thisEntity.noPhysics = intangible
DoubleValue.ONE
},
}
)
@@ -39,7 +39,6 @@ import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.behavior.EntityTracker
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.memory.WalkTarget
@@ -124,23 +123,6 @@ object LivingEntityMoLangFunctions : AbstractMoLangFunctionHolder<LivingEntity>(
duration.toLong()
)
}
map["look_at_entity"] = put@{ params ->
val targetEntity = params.get<MoValue>(0)
val duration = params.getDoubleOrNull(1)?.toInt() ?: 20
val lookEntity = if (targetEntity is ObjectValue<*> && targetEntity.obj is Entity) {
targetEntity.obj as Entity
} else {
return@put DoubleValue.ZERO
}
// Set the current entity to track the looked for entity
val brain = entity.brain
val tracker = EntityTracker(lookEntity, true)
brain.setMemoryWithExpiry(MemoryModuleType.LOOK_TARGET, tracker, duration.toLong())
DoubleValue.ONE
}
map["get_wander_control_memory"] = put@{
val value = entity.brain.getMemorySafely(CobblemonMemories.WANDER_CONTROL).orElse(null)
?: CobblemonWanderControl()
@@ -23,7 +23,6 @@ import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
@@ -33,7 +32,6 @@ import com.cobblemon.mod.common.util.activeDialogue
import com.cobblemon.mod.common.util.asBlockPos
import com.cobblemon.mod.common.util.asResource
import com.cobblemon.mod.common.util.asUUID
import com.cobblemon.mod.common.util.blockRegistry
import com.cobblemon.mod.common.util.getBattleState
import com.cobblemon.mod.common.util.getBooleanOrNull
import com.cobblemon.mod.common.util.getDoubleOrNull
@@ -46,19 +44,14 @@ import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.pc
import com.cobblemon.mod.common.util.pokedex
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.util.toArrayStruct
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.ClipContext
import net.minecraft.world.level.GameType
import net.minecraft.world.phys.HitResult
import kotlin.collections.iterator
object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
@@ -386,61 +379,6 @@ object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
} ?: DoubleValue.ZERO
}
map["has_chosen_starter"] = { _ -> DoubleValue(Cobblemon.playerDataManager.getGenericData(player).starterSelected) }
map["ride"] = put@{ params ->
val entity = (params.get<MoValue>(0) as? ObjectValue<*>)?.obj as? Entity ?: return@put DoubleValue.ZERO
player.startRiding(entity)
}
map["has_respawn_position"] = {
DoubleValue(player.respawnPosition != null)
}
map["respawn_position"] = {
player.respawnPosition?.toArrayStruct() ?: DoubleValue.ZERO
}
map["respawn_dimension"] = {
StringValue(player.respawnDimension.location().toString())
}
map["teleport_to_respawn"] = put@{
val respawnPosition = player.respawnPosition?.center ?: return@put DoubleValue.ZERO
player.teleportTo(respawnPosition.x, respawnPosition.y, respawnPosition.z)
DoubleValue.ONE
}
map["get_looked_block"] = put@{ params ->
// Get the block the player is looking at 'distance' units away
val distance = params.getDoubleOrNull(0) ?: 8.0
// perform clip
val level = player.level()
val eye = player.eyePosition
val view = player.getViewVector(1.0f)
val lookPos = eye.add(view.scale(distance))
val hitResult = level.clip(ClipContext(eye, lookPos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player))
if (hitResult.type == HitResult.Type.BLOCK) {
// Get base block info
val blockPos = hitResult.blockPos
val blockState = level.getBlockState(blockPos)
val blockHolder = level.blockRegistry.wrapAsHolder(blockState.block)
val blockValue = blockHolder.asMoLangValue(Registries.BLOCK)
// Attach the position to the blockValue return
blockValue.addFunction("x") { DoubleValue(blockPos.x.toDouble()) }
blockValue.addFunction("y") { DoubleValue(blockPos.y.toDouble()) }
blockValue.addFunction("z") { DoubleValue(blockPos.z.toDouble()) }
return@put blockValue
} else {
return@put DoubleValue.ZERO
}
}
map["is_battling"] = {
DoubleValue(player.isInBattle())
}
}
if (player is AbstractClientPlayer) {
map["is_battling"] = {
DoubleValue(CobblemonClient.battle?.spectating == false) // Checks not-null and not-spectating at the same time, trust
}
}
return map
@@ -15,7 +15,6 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonMovesetBuilders
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.api.mark.Marks
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.moves.BenchedMove
@@ -27,9 +26,6 @@ import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.storage.party.PartyStore
import com.cobblemon.mod.common.pokemon.IVs
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ActivePokemonState
import com.cobblemon.mod.common.pokemon.activestate.SentOutState
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.util.asArrayValue
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.getBooleanOrNull
@@ -451,29 +447,6 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
evolution?.forceEvolve(pokemon)
StringValue(evolution.toString())
}
map["is_sent_out"] = {
DoubleValue(pokemon.state is SentOutState)
}
map["is_shouldered"] = {
DoubleValue(pokemon.state is ShoulderedState)
}
map["entity"] = {
(pokemon.state as? ActivePokemonState)?.entity?.struct ?: DoubleValue.ZERO
}
map["is_rideable"] = put@{
return@put DoubleValue(!pokemon.riding.behaviours.isNullOrEmpty())
}
map["has_status"] = put@{ params ->
val status = params.getString(0).asIdentifierDefaultingNamespace()
return@put DoubleValue(pokemon.status?.status?.name == status)
}
map["add_skill_cooldown"] = put@{ params ->
val skillId = params.getString(0).asIdentifierDefaultingNamespace()
val cooldownTicks = params.getIntOrNull(1)
val skill = CobblemonPokeSkills.skills[skillId] ?: return@put DoubleValue.ZERO
pokemon.addSkillCooldown(skillId, cooldownTicks ?: skill.cooldownTicks)
return@put DoubleValue.ONE
}
map["entity"] = { pokemon.entity?.asMoLangValue() ?: DoubleValue.ZERO }
map["is_alpha"] = { DoubleValue(pokemon.isAlpha) }
@@ -40,7 +40,6 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.Level.ExplosionInteraction
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity
import net.minecraft.world.level.levelgen.Heightmap
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
@@ -62,26 +61,6 @@ object WorldMoLangFunctions : AbstractMoLangFunctionHolder<Holder<Level>>() {
val time = world.dayTime % 24000
return@put DoubleValue(timeOfDay.contains(time.toInt()))
}
map["add_furnace_fuel"] = put@{ params ->
val x = params.getInt(0)
val y = params.getInt(1)
val z = params.getInt(2)
val fuelTicks = params.getInt(3)
val blockEntity = world.getBlockEntity(BlockPos(x, y, z))
if (blockEntity is AbstractFurnaceBlockEntity) {
// Add fuel time to the furnace
blockEntity.litTime += fuelTicks
// If this exceeds the litDuration then bump it up
if (blockEntity.litTime >= blockEntity.litDuration) {
blockEntity.litDuration = blockEntity.litTime
}
blockEntity.setChanged()
return@put DoubleValue.ONE
}
return@put DoubleValue.ZERO
}
map["game_time"] = { _ -> DoubleValue(world.gameTime.toDouble()) }
map["time_of_day"] = put@{
val time = world.dayTime % 24000
@@ -149,13 +128,13 @@ object WorldMoLangFunctions : AbstractMoLangFunctionHolder<Holder<Level>>() {
val x = params.getDouble(0)
val y = params.getDouble(1)
val z = params.getDouble(2)
val range = params.getDoubleOrNull(3) ?: 8.0
val range = params.getDouble(3).toFloat()
world.explode(
null,
x,
y,
z,
range.toFloat(),
range,
ExplosionInteraction.valueOf(
params.getStringOrNull(4)?.uppercase() ?: ExplosionInteraction.TNT.name
)
@@ -50,7 +50,7 @@ class ActionEffectTimeline(
}
fun chainKeyframes(context: ActionEffectContext, iterator: Iterator<ActionEffectKeyframe>, finalFuture: CompletableFuture<Unit>) {
if (!iterator.hasNext() || context.cancelled) {
if (!iterator.hasNext()) {
finalFuture.complete(Unit)
} else {
val keyframe = iterator.next()
@@ -70,7 +70,6 @@ class ActionEffectContext(
val runtime: MoLangRuntime,
var canBeInterrupted: Boolean = false,
var interrupted: Boolean = false,
var cancelled: Boolean = false,
var currentKeyframes: MutableList<ActionEffectKeyframe> = mutableListOf(),
var level: Level? = null
) {
@@ -57,7 +57,6 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
ActionEffectKeyframe.register<RunActionEffectKeyframe>("run_action_effect")
ActionEffectKeyframe.register<EntityParticlesActionEffectKeyframe>("entity_particles")
ActionEffectKeyframe.register<EntitySoundActionEffectKeyframe>("entity_sound")
ActionEffectKeyframe.register<CancelActionEffectKeyframe>("cancel")
}
override val gson = GsonBuilder()
@@ -1,19 +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.moves.animations.keyframes
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import java.util.concurrent.CompletableFuture
class CancelActionEffectKeyframe : ConditionalActionEffectKeyframe() {
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
context.cancelled = true
return CompletableFuture.completedFuture(Unit)
}
}
@@ -21,7 +21,6 @@ import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.commands.arguments.EntityArgument.getPlayers
import java.util.concurrent.CompletableFuture
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.phys.Vec3
/**
* Spawns particles on the entity based on the given particle effect and locator.
@@ -66,36 +65,15 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
allEntities.any { player.distanceTo(it) <= visibilityRange }
}
// Try to resolve a world-position target from runtime variables
val runtimeTargetPosition: Vec3? = try {
val x = "v.target_x".asExpressionLike().resolveDouble(context.runtime)
val y = "v.target_y".asExpressionLike().resolveDouble(context.runtime)
val z = "v.target_z".asExpressionLike().resolveDouble(context.runtime)
if (x != 0.0 || y != 0.0 || z != 0.0) Vec3(x, y, z) else null
} catch (e: Exception) {
null
}
sourceEntities.filter { it is PosableEntity }.forEach { entity ->
// If target entities are specified, send the particle using entity locators/position.
// If there are no target entities then attempt to send to v.target world position or send without target.
if (targetEntities.isNotEmpty()) {
if (targetLocators == null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators)
packet.sendToPlayers(players)
}
else {
targetEntities.forEach { targetEntity ->
if (targetLocators != null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id, targetLocators!!.toList())
packet.sendToPlayers(players)
} else {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id)
packet.sendToPlayers(players)
}
}
} else {
if (runtimeTargetPosition != null) {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetPosition = runtimeTargetPosition)
packet.sendToPlayers(players)
} else {
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators)
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locators, targetEntity.id, targetLocators!!.toList())
packet.sendToPlayers(players)
}
}
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.moves.animations.keyframes
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.scheduling.delayedFuture
@@ -8,8 +8,6 @@
package com.cobblemon.mod.common.api.moves.animations.keyframes
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import java.util.concurrent.CompletableFuture
@@ -20,37 +18,16 @@ import net.minecraft.resources.ResourceLocation
* effect is marked complete only when the action effect it runs is complete unless [waitForActionEffect] is
* false.
*
* If [expression] is set, it will be resolved at runtime to determine the action effect identifier.
* This allows dynamic delegation based on MoLang variables (e.g. v.granting_move).
* If [expression] is not set, the static [actionEffect] identifier is used instead.
*
* @author Hiroku
* @since January 21st, 2024
*/
class RunActionEffectKeyframe : ConditionalActionEffectKeyframe() {
val actionEffect: ResourceLocation? = null
val expression: ExpressionLike? = null
val waitForActionEffect = true
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
val effectId = if (expression != null) {
val resolved = expression.resolveString(context.runtime)
if (resolved == "0" || resolved.isBlank()) {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe expression resolved to empty/zero string: $resolved")
return skip()
}
try {
ResourceLocation.parse(resolved)
} catch (e: Exception) {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe expression resolved to invalid resource location: $resolved with exception: $e")
return skip()
}
return if (actionEffect != null) {
ActionEffects.actionEffects[actionEffect]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
} else {
actionEffect
}
return if (effectId != null) {
ActionEffects.actionEffects[effectId]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
} else {
Cobblemon.LOGGER.warn("RunActionEffectKeyframe has no action effect identifier or expression to run")
skip()
}
}
@@ -759,7 +759,6 @@ open class PokemonProperties {
shiny?.let { json.addProperty(DataKeys.POKEMON_SHINY, it) }
gender?.let { json.addProperty(DataKeys.POKEMON_GENDER, it.name) }
species?.let { json.addProperty(DataKeys.POKEMON_SPECIES_TEXT, it) }
nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, it.string) }
form?.let { json.addProperty(DataKeys.POKEMON_FORM_ID, it) }
friendship?.let { json.addProperty(DataKeys.POKEMON_FRIENDSHIP, it) }
fullness?.let { json.addProperty(DataKeys.POKEMON_FULLNESS, it) }
@@ -796,7 +795,6 @@ open class PokemonProperties {
shiny = json.get(DataKeys.POKEMON_SHINY)?.asBoolean
gender = json.get(DataKeys.POKEMON_GENDER)?.asString?.let { Gender.valueOf(it) }
species = json.get(DataKeys.POKEMON_SPECIES_TEXT)?.asString
nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let(Component::literal)
form = json.get(DataKeys.POKEMON_FORM_ID)?.asString
friendship = json.get(DataKeys.POKEMON_FRIENDSHIP)?.asInt
fullness = json.get(DataKeys.POKEMON_FULLNESS)?.asInt
@@ -102,7 +102,7 @@ open class PlayerPartyStore(
for (pokemon in this) {
// Awake from fainted
if (pokemon.isFainted()) {
// Skip awaken logic check if config value is 0
//Skip awaken logic check if config value is 0
if (Cobblemon.config.faintAwakenHealthPercent > 0) {
pokemon.faintedTimer -= 1
if (pokemon.faintedTimer <= -1) {
@@ -119,7 +119,7 @@ open class PlayerPartyStore(
}
// Passive healing while less than full health
else if (pokemon.currentHealth < pokemon.maxHealth) {
// Skip passive healing logic check if config value is 0
//Skip passive healing logic check if config value is 0
if (Cobblemon.config.healPercent > 0) {
pokemon.healTimer--
if (pokemon.healTimer <= -1) {
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.moves.adapters.MoveTemplateAdapter
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.TMObtainMethodAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
@@ -71,7 +70,5 @@ object TechnicalMachines : JsonDataRegistry<TechnicalMachine> {
fun getByResourceLocation(resourceLocation: ResourceLocation) = tmMap[resourceLocation]
fun getAllResourceLocations() = tmMap.keys.toSet()
override fun sync(player: ServerPlayer) {
TechnicalMachineRegistrySyncPacket(tmMap.values.toList()).sendToPlayer(player)
}
override fun sync(player: ServerPlayer) {}
}
@@ -16,20 +16,24 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.core.NonNullList
import net.minecraft.core.component.DataComponents
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundSource
import net.minecraft.world.*
import net.minecraft.world.ContainerHelper
import net.minecraft.world.Containers
import net.minecraft.world.InteractionResult
import net.minecraft.world.ItemInteractionResult
import net.minecraft.world.WorldlyContainer
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.phys.BlockHitResult
import java.util.*
import net.minecraft.world.level.gameevent.GameEvent
import java.util.OptionalInt
import kotlin.math.pow
class DiscShelfBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(CobblemonBlockEntities.DISC_SHELF, pos, state), WorldlyContainer {
@@ -130,7 +134,25 @@ class DiscShelfBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobbl
return stack.item is TechnicalMachineItem
|| stack.item == CobblemonItems.UPGRADE
|| stack.item == CobblemonItems.DUBIOUS_DISC
|| stack.has(DataComponents.JUKEBOX_PLAYABLE)
|| stack.item == Items.MUSIC_DISC_13
|| stack.item == Items.MUSIC_DISC_CAT
|| stack.item == Items.MUSIC_DISC_BLOCKS
|| stack.item == Items.MUSIC_DISC_CHIRP
|| stack.item == Items.MUSIC_DISC_FAR
|| stack.item == Items.MUSIC_DISC_MALL
|| stack.item == Items.MUSIC_DISC_MELLOHI
|| stack.item == Items.MUSIC_DISC_STAL
|| stack.item == Items.MUSIC_DISC_STRAD
|| stack.item == Items.MUSIC_DISC_WARD
|| stack.item == Items.MUSIC_DISC_11
|| stack.item == Items.MUSIC_DISC_WAIT
|| stack.item == Items.MUSIC_DISC_OTHERSIDE
|| stack.item == Items.MUSIC_DISC_5
|| stack.item == Items.MUSIC_DISC_RELIC
|| stack.item == Items.MUSIC_DISC_PRECIPICE
|| stack.item == Items.MUSIC_DISC_CREATOR
|| stack.item == Items.MUSIC_DISC_CREATOR_MUSIC_BOX
|| stack.item == Items.MUSIC_DISC_PIGSTEP
}
fun onNoteBlockPulse(level: Level, noteBlockPos: BlockPos, soundEvent: SoundEvent) {
@@ -630,8 +630,7 @@ class FossilMultiblockStructure (
result.putInt(DataKeys.ORGANIC_MATERIAL, organicMaterialInside)
val fossilInv = ListTag()
val ops = registryLookup.createSerializationContext(NbtOps.INSTANCE)
fossilInventory.forEach { fossilInv.add(ItemStack.CODEC.encodeStart(ops, it).getOrThrow()) }
fossilInventory.forEach { fossilInv.add(ItemStack.CODEC.encodeStart(NbtOps.INSTANCE, it).orThrow) }
result.put(DataKeys.FOSSIL_INVENTORY, fossilInv)
result.putString(DataKeys.CONNECTOR_DIRECTION, tankConnectorDirection?.toString())
@@ -670,10 +669,7 @@ class FossilMultiblockStructure (
val fossilInv = if (nbt.contains(DataKeys.FOSSIL_INVENTORY)) { (nbt.get(DataKeys.FOSSIL_INVENTORY) as ListTag) } else ListTag()
val actualFossilList = mutableListOf<ItemStack>()
val ops = registryLookup.createSerializationContext(NbtOps.INSTANCE)
fossilInv.forEach { ItemStack.CODEC.parse(ops, it).result().ifPresent(actualFossilList::add) }
fossilInv.forEach { ItemStack.parse(registryLookup, it).ifPresent(actualFossilList::add) }
result.fossilInventory = actualFossilList
result.tankConnectorDirection = Direction.byName(nbt.getString(DataKeys.CONNECTOR_DIRECTION))
@@ -179,8 +179,6 @@ object CobblemonClient {
return@subscribe
}
storage.party.forEach { it?.tickSkillCooldowns() }
val nearbyPokemon = player.level().getEntities(
player,
AABB.ofSize(player.position(), 16.0, 16.0, 16.0)
@@ -28,7 +28,7 @@ class InteractWheelButton(
private val tooltipText: String?,
x: Int,
y: Int,
private val isEnabled: () -> Boolean,
private val isEnabled: Boolean,
private val colour: () -> Vector3f?,
onPress: OnPress,
private val canHover: (Double, Double) -> Boolean
@@ -74,12 +74,12 @@ class InteractWheelButton(
y = y,
width = width,
height = height,
vOffset = if (isHovered(mouseX.toFloat(), mouseY.toFloat()) && isEnabled()) height else 0,
vOffset = if (isHovered(mouseX.toFloat(), mouseY.toFloat()) && isEnabled) height else 0,
textureHeight = height * 2,
alpha = if (isEnabled()) 1f else 0.4F
alpha = if (isEnabled) 1f else 0.4F
)
if (isEnabled() && isHovered(mouseX.toFloat(), mouseY.toFloat())){
if(isEnabled && isHovered(mouseX.toFloat(), mouseY.toFloat())){
tooltipText?.let {
context.renderTooltip(Minecraft.getInstance().font, Component.translatable(it), mouseX, mouseY)
}
@@ -95,7 +95,7 @@ class InteractWheelButton(
y = iconY,
width = ICON_SIZE,
height = ICON_SIZE,
alpha = if (isEnabled()) 1F else 0.2F,
alpha = if (isEnabled) 1F else 0.2F,
red = colour.x,
green = colour.y,
blue = colour.z,
@@ -114,7 +114,7 @@ class InteractWheelButton(
y = iconY - ICON_SIZE,
width = ICON_SIZE,
height = ICON_SIZE,
alpha = if (isEnabled()) 1F else 0.4F,
alpha = if (isEnabled) 1F else 0.4F,
red = colour.x,
green = colour.y,
blue = colour.z,
@@ -18,7 +18,7 @@ import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import kotlin.math.max
open class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelOption>, title: Component) : Screen(title), CobblemonRenderable {
class InteractWheelGUI(private val options: Multimap<Orientation, InteractWheelOption>, title: Component) : Screen(title), CobblemonRenderable {
companion object {
const val SIZE = 170
private val backgroundResource = cobblemonResource("textures/gui/interact/interact_wheel_base.png")
@@ -32,7 +32,7 @@ open class InteractWheelGUI(private val options: Multimap<Orientation, InteractW
return super.keyPressed(keyCode, scanCode, modifiers)
}
protected val buttons = mutableListOf<InteractWheelButton>()
private val buttons = mutableListOf<InteractWheelButton>()
private var maxPage = 1
private var currentPage = 0
override fun renderBlurredBackground(delta: Float) { }
@@ -104,7 +104,7 @@ open class InteractWheelGUI(private val options: Multimap<Orientation, InteractW
tooltipText = option?.tooltipText,
x = x,
y = y,
isEnabled = { option != null && option.enabled() },
isEnabled = option != null && option.enabled,
colour = option?.colour ?: { null },
onPress = { option?.onPress?.invoke() },
canHover = { a: Double, b: Double -> !isMouseInCenter(a, b)}
@@ -9,24 +9,20 @@
package com.cobblemon.mod.common.client.gui.interact.wheel
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.gui.interact.battleRequest.BattleConfigureGUI
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.server.UsePokeSkillPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.Multimap
import java.util.UUID
import net.minecraft.client.Minecraft
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.network.chat.Component
import org.joml.Vector3f
@@ -34,7 +30,7 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canGive
val mountShoulder = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/interact_wheel_icon_shoulder.png"),
tooltipText = "cobblemon.ui.interact.mount.shoulder",
enabled = { canMountShoulder },
enabled = canMountShoulder,
onPress = {
if (canMountShoulder) {
InteractPokemonPacket(pokemonID, InteractTypePokemon.SHOULDER).sendToServer()
@@ -45,7 +41,7 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canGive
val giveHeldItem = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/interact_wheel_icon_held_item.png"),
tooltipText = "cobblemon.ui.interact.give.item",
enabled = { canGiveHeld },
enabled = canGiveHeld,
onPress = {
if (canGiveHeld) {
InteractPokemonPacket(pokemonID, InteractTypePokemon.HELD_ITEM).sendToServer()
@@ -56,7 +52,7 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canGive
val giveCosmeticItem = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/interact_wheel_icon_cosmetic_item.png"),
tooltipText = "cobblemon.ui.interact.give.cosmetic_item",
enabled = { canGiveCosmetic },
enabled = canGiveCosmetic,
onPress = {
if (canGiveCosmetic) {
InteractPokemonPacket(pokemonID, InteractTypePokemon.COSMETIC_ITEM).sendToServer()
@@ -68,7 +64,7 @@ fun createPokemonInteractGui(pokemonID: UUID, canMountShoulder: Boolean, canGive
val ride = InteractWheelOption(
iconResource = cobblemonResource("textures/gui/interact/interact_wheel_icon_ride.png"),
tooltipText = "cobblemon.ui.interact.ride",
enabled = { canRide },
enabled = canRide,
onPress = {
if (canRide) {
InteractPokemonPacket(pokemonID, InteractTypePokemon.RIDE).sendToServer()
@@ -181,35 +177,6 @@ fun createPlayerInteractGui(optionsPacket: PlayerInteractOptionsPacket): Interac
return InteractWheelGUI(options, Component.translatable("cobblemon.ui.interact.player"))
}
fun createPokeSkillGui(player: AbstractClientPlayer, pokemon: Pokemon): InteractWheelGUI {
val accessibleSkills = CobblemonPokeSkills.getAccessibleSkills(player, pokemon)
val options: Multimap<Orientation, InteractWheelOption> = ArrayListMultimap.create()
for (skill in accessibleSkills) {
val skillOption = InteractWheelOption(
iconResource = skill.icon,
enabled = { skill.id !in pokemon.skillCooldownsTicks },
tooltipText = skill.name,
onPress = {
CobblemonNetwork.sendToServer(UsePokeSkillPacket(skillId = skill.id, pokemonId = pokemon.uuid))
closeGUI()
}
)
when (options.size()) {
0 -> options.put(Orientation.NORTH, skillOption)
1 -> options.put(Orientation.NORTHEAST, skillOption)
2 -> options.put(Orientation.SOUTHEAST, skillOption)
3 -> options.put(Orientation.SOUTH, skillOption)
4 -> options.put(Orientation.SOUTHWEST, skillOption)
5 -> options.put(Orientation.NORTHWEST, skillOption)
6 -> options.put(Orientation.WEST, skillOption)
7 -> options.put(Orientation.EAST, skillOption)
else -> break // We only have 8 slots
}
}
return PokeSkillWheelGUI(options, Component.translatable("cobblemon.ui.interact.poke_skill"))
}
private fun getLangKey(status: PlayerInteractOptionsPacket.OptionStatus) : String {
return when (status) {
PlayerInteractOptionsPacket.OptionStatus.TOO_FAR -> "cobblemon.ui.interact.too_far"
@@ -14,7 +14,7 @@ import org.joml.Vector3f
data class InteractWheelOption(
val iconResource: ResourceLocation,
val secondaryIconResource: ResourceLocation? = null,
val enabled: () -> Boolean = { true },
val enabled: Boolean = true,
val tooltipText: String?,
val colour: () -> Vector3f? = { null },
val onPress: () -> Unit
@@ -1,47 +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.interact.wheel
import com.google.common.collect.Multimap
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
class PokeSkillWheelGUI(
private val options: Multimap<Orientation, InteractWheelOption>,
title: Component
) : InteractWheelGUI(options, title) {
/**
* Due to the button being held swallow the event
*/
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (button == 0) return false
return super.mouseClicked(mouseX, mouseY, button)
}
/**
* On release will close the wheel and trigger the button press of the hovered button
* TODO: make this wheel choose more like pizza slices.
*/
override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (button == 0) {
// Manually trigger the hovered button's press
buttons.forEach { btn ->
if (btn.isMouseOver(mouseX, mouseY)) {
btn.onClick(mouseX, mouseY)
return true
}
}
Minecraft.getInstance().setScreen(null)
return true
}
return super.mouseReleased(mouseX, mouseY, button)
}
}
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.ClientBattle
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.gui.interact.wheel.createPokeSkillGui
import com.cobblemon.mod.common.client.keybind.CobblemonBlockingKeyBinding
import com.cobblemon.mod.common.client.keybind.KeybindCategories
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
@@ -27,12 +26,12 @@ import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.isUsingPokedex
import com.cobblemon.mod.common.util.traceFirstEntityCollision
import com.mojang.blaze3d.platform.InputConstants
import kotlin.math.pow
import net.minecraft.client.Minecraft
import net.minecraft.client.player.LocalPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.ClipContext
import kotlin.math.pow
object PartySendBinding : CobblemonBlockingKeyBinding(
"key.cobblemon.throwpartypokemon",
@@ -40,17 +39,32 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
InputConstants.KEY_R,
KeybindCategories.COBBLEMON_CATEGORY
) {
const val POKE_SKILL_TIME = 0.7F
var canApplyChange = true
var heldDownSeconds = 0F
fun actioned() {
canApplyChange = false
wasDown = true
heldDownSeconds = 0F
}
fun canAction() = canApplyChange && Minecraft.getInstance().player?.isUsingPokedex() == false
override fun onTick() {
if (wasDown) {
if (heldDownSeconds < 100) {
heldDownSeconds += Minecraft.getInstance().timer.getGameTimeDeltaPartialTick(false)
}
} else {
heldDownSeconds = 0F
}
super.onTick()
}
override fun onRelease() {
val canAction = canAction()
wasDown = false
canApplyChange = true
if (!canAction) {
return
@@ -91,8 +105,7 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
entityClass = LivingEntity::class.java,
ignoreEntity = player,
maxDistance = Cobblemon.config.battleSpectateMaxDistance,
collideBlock = ClipContext.Fluid.NONE
)
collideBlock = ClipContext.Fluid.NONE)
if (canSendOutPokemon(player, targetEntity)) {
sendToServer(SendOutPokemonPacket(CobblemonClient.storage.selectedSlot))
} else {
@@ -114,13 +127,10 @@ object PartySendBinding : CobblemonBlockingKeyBinding(
//The server sends a packet back that opens the player interaction menu with the proper options
sendToServer(RequestPlayerInteractionsPacket(entity.uuid, entity.id, pokemon.uuid))
}
is PokemonEntity -> {
if (!entity.canBattle(player) || entity.position()
.distanceToSqr(player.position()) > Cobblemon.config.battleWildMaxDistance.pow(2)
) return
sendToServer(BattleChallengePacket(entity.id, pokemon.uuid, BattleFormat.GEN_9_SINGLES))
}
if (!entity.canBattle(player) || entity.position().distanceToSqr(player.position()) > Cobblemon.config.battleWildMaxDistance.pow(2)) return
sendToServer(BattleChallengePacket(entity.id, pokemon.uuid, BattleFormat.GEN_9_SINGLES))
}
}
}
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import net.minecraft.client.Minecraft
import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3
object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSnowstormEntityParticlePacket> {
override fun handle(packet: SpawnSnowstormEntityParticlePacket, client: Minecraft) {
@@ -32,7 +31,6 @@ object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSno
val targetState = (targetedEntity as? PosableEntity)?.delegate as? PosableState
val sourceLocators = packet.sourceLocators.firstNotNullOfOrNull { sourceState.getMatchingLocators(it).takeIf { it.isNotEmpty() } } ?: return
val targetedLocator = packet.targetLocators?.firstOrNull { targetState?.getMatchingLocators(it)?.isNotEmpty() == true }
val targetPosition = packet.targetPosition
val rootMatrix = sourceState.locatorStates["root"]!!
sourceLocators.forEach { locator ->
@@ -42,16 +40,6 @@ object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSno
val particleRuntime = MoLangRuntime().setup().setupClient()
particleRuntime.environment.query.addFunction("entity") { sourceState.runtime.environment.query }
// Target resolution priority: entity+locator > world position > none
val targetPos: (() -> Vec3)? = if (targetedEntity != null) {
{ targetedLocator?.let { targetState?.locatorStates?.get(it) }?.getOrigin() ?: targetedEntity.position() }
} else if (targetPosition != null) {
val pos = packet.targetPosition
{ pos }
} else {
null
}
val storm = ParticleStorm(
effect = effect,
emitterSpaceMatrix = particleMatrix,
@@ -61,7 +49,7 @@ object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSno
sourceVelocity = { sourceEntity.deltaMovement },
sourceAlive = { !sourceEntity.isRemoved },
sourceVisible = { !sourceEntity.isInvisible },
targetPos = targetPos,
targetPos = if (targetedEntity != null) { { targetedLocator?.let { targetState?.locatorStates?.get(it) }?.getOrigin() ?: targetedEntity.position() } } else null,
entity = sourceEntity
)
@@ -22,8 +22,6 @@ object ServerSettingsPacketHandler : ClientNetworkPacketHandler<ServerSettingsPa
ServerSettings.maxPokemonFriendship = packet.maxPokemonFriendship
ServerSettings.maxDynamaxLevel = packet.maxDynamaxLevel
ServerSettings.unlockAllMoveDexMovesByDefault = packet.unlockAllMoveDexMovesByDefault
ServerSettings.pokemonIntrinsicSizeMin = packet.pokemonIntrinsicSizeMin
ServerSettings.pokemonIntrinsicSizeMax = packet.pokemonIntrinsicSizeMax
}
}
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.blaze3d.vertex.PoseStack
import com.mojang.blaze3d.vertex.VertexConsumer
import com.mojang.math.Axis
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.LevelRenderer
import net.minecraft.client.renderer.MultiBufferSource
import net.minecraft.client.renderer.RenderType
@@ -40,13 +39,13 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
private val leftMargin = 1f
private val rightMargin = 1f
private val topMargin = 1f
private val bottomMargin = 1f
private val interRowSpacing = 0f
private val tmOverlayDepthOffset = -0.0002f
private val slotBrightnessMultiplier = 0.65f
private val tmBaseTexture = cobblemonResource("textures/block/disc_shelf/technical_machine_base.png")
private val tmOverlayTexture = cobblemonResource("textures/block/disc_shelf/technical_machine_overlay.png")
private val musicDiscUnknownTexture = cobblemonResource("textures/block/disc_shelf/music_disc_unknown.png")
override fun render(
entity: DiscShelfBlockEntity,
@@ -78,6 +77,7 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
val slotWidth = slotWidthPixels / textureSize
val slotHeight = slotHeightPixels / textureSize
val verticalSpacing = (slotHeightPixels + interRowSpacing) / textureSize
val totalHeight = slotHeight * 7 + interRowSpacing * 6 / textureSize
val startY = topMargin / textureSize
for ((index, item) in entity.items.withIndex()) {
@@ -188,13 +188,6 @@ class DiscShelfBlockEntityRenderer(ctx: BlockEntityRendererProvider.Context) :
private fun getItemTexture(itemStack: ItemStack): ResourceLocation {
val id = BuiltInRegistries.ITEM.getKey(itemStack.item)
val resource = cobblemonResource("textures/block/disc_shelf/${id.path}.png")
val resourceManager = Minecraft.getInstance().resourceManager
if (resourceManager.getResource(resource).isEmpty) {
return musicDiscUnknownTexture
}
return resource
return cobblemonResource("textures/block/disc_shelf/${id.path}.png")
}
}
@@ -1,93 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.util.isInWater
import net.minecraft.client.model.geom.ModelPart
import net.minecraft.world.phys.Vec3
class TentacoolModel(root: ModelPart) : PokemonPosableModel(root) {
override val rootPart = root.registerChildWithAllChildren("tentacool")
override var portraitScale = 1.2F
override var portraitTranslation = Vec3(0.1, 1.1, 0.0)
override var profileScale = 0.6F
override var profileTranslation = Vec3(0.0, 0.8, 0.0)
lateinit var standing: CobblemonPose
lateinit var walk: CobblemonPose
lateinit var swim: CobblemonPose
lateinit var float: CobblemonPose
lateinit var sleep: CobblemonPose
lateinit var watersleep: CobblemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("tentacool", "blink")}
standing = registerPose(
poseName = "standing",
poseType = PoseType.STAND,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("tentacool", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseType = PoseType.WALK,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("tentacool", "ground_idle")
//bedrock("tentacool", "ground_walk")
)
)
float = registerPose(
poseName = "float",
poseTypes = UI_POSES + PoseType.FLOAT,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("tentacool", "water_idle")
)
)
swim = registerPose(
poseName = "swim",
poseType = PoseType.SWIM,
quirks = arrayOf(blink),
animations = arrayOf(
bedrock("tentacool", "water_swim")
)
)
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
condition = { !it.isInWater },
animations = arrayOf(bedrock("tentacool", "sleep"))
)
watersleep = registerPose(
poseName = "watersleep",
poseType = PoseType.SLEEP,
condition = { it.isInWater },
animations = arrayOf(bedrock("tentacool", "water_sleep"))
)
}
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PosableState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("tentacool", "faint") else null
}
@@ -285,7 +285,6 @@ object VaryingModelRepository {
inbuilt("rapidash", ::RapidashModel)
inbuilt("sandslash", ::SandslashModel)
inbuilt("tangela", ::TangelaModel)
inbuilt("tentacool", ::TentacoolModel)
inbuilt("venomoth", ::VenomothModel)
inbuilt("venonat", ::VenonatModel)
inbuilt("elekid", ::ElekidModel)
@@ -28,7 +28,5 @@ object ServerSettings {
var maxPokemonFriendship = Cobblemon.config.maxPokemonFriendship
var maxDynamaxLevel = Cobblemon.config.maxDynamaxLevel
var unlockAllMoveDexMovesByDefault = Cobblemon.config.unlockAllMoveDexMovesByDefault
var pokemonIntrinsicSizeMin = Cobblemon.config.pokemonIntrinsicSizeMin
var pokemonIntrinsicSizeMax = Cobblemon.config.pokemonIntrinsicSizeMax
}
@@ -243,6 +243,18 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Pokemon, lang = "pokemon_intrinsic_size_max", SERVER)
var pokemonIntrinsicSizeMax = 1.05F
@CobblemonConfigField(Category.Pokemon, lang = "alpha_pokemon_size_small_multiplier", SERVER)
var alphaPokemonSizeSmallMultiplier = 1.70F
@CobblemonConfigField(Category.Pokemon, lang = "alpha_pokemon_size_medium_multiplier", SERVER)
var alphaPokemonSizeMediumMultiplier = 1.55F
@CobblemonConfigField(Category.Pokemon, lang = "alpha_pokemon_size_large_multiplier", SERVER)
var alphaPokemonSizeLargeMultiplier = 1.40F
@CobblemonConfigField(Category.Pokemon, lang = "alpha_pokemon_size_extra_large_multiplier", SERVER)
var alphaPokemonSizeExtraLargeMultiplier = 1.25F
@CobblemonConfigField(Category.Pokemon, lang = "baby_pokemon_level_duration", SERVER)
var babyPokemonLevelDuration = 9
@@ -335,6 +347,9 @@ class CobblemonConfig {
// @CobblemonConfigField(Category.Riding, lang = "third_person_view_bobbing", CLIENT)
var thirdPersonViewBobbing = true
@CobblemonConfigField(Category.Riding, lang = "invert_roll", CLIENT)
var invertRoll = false
@CobblemonConfigField(Category.Riding, lang = "invert_pitch", CLIENT)
var invertPitch = false
@@ -350,6 +365,9 @@ class CobblemonConfig {
@CobblemonConfigField(Category.Riding, lang = "swap_x_and_y_axes", CLIENT)
var swapXAndYAxes = false
@CobblemonConfigField(Category.Riding, lang = "automatic_righting_delay", CLIENT)
var rightingDelay = -1.0
@CobblemonConfigField(Category.Riding, lang = "disable_roll", CLIENT)
var disableRoll = false
@@ -10,13 +10,6 @@ package com.cobblemon.mod.common.data
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.CobblemonBehaviours
import com.cobblemon.mod.common.CobblemonCallbacks
import com.cobblemon.mod.common.CobblemonCosmeticItems
import com.cobblemon.mod.common.CobblemonMechanics
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.CobblemonRideSettings
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.api.cooking.Seasonings
@@ -80,7 +73,6 @@ object CobblemonDataProvider : DataProvider {
this.register(GlobalSpeciesFeatures, reloadable = false)
this.register(SpeciesFeatureAssignments, reloadable = false)
this.register(ActionEffects, reloadable = true)
this.register(CobblemonPokeSkills, reloadable = true)
this.register(Moves, reloadable = false)
this.register(CobblemonMovesetBuilders, reloadable = false)
this.register(Abilities, reloadable = false)
@@ -1,360 +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.entity.pokemon
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.blockRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.codec.EXPRESSION_LIKE_CODEC
import com.cobblemon.mod.common.util.isInBattle
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.registries.Registries
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.HitResult
/**
* The reference object for a skill that a Pokémon can use in the overworld.
*
* Most skills are "wrapper" skills that play a move's action effect at a target and run
* some MoLang on impact. Custom skills can define a full action effect timeline.
*
* Access is auto-derived from grantingMoves/Abilities/Types/Species lists. If none are
* populated, accessCondition is used as a fallback.
*
* @author Hiroku
* @since August 31st, 2025
*/
class PokeSkill(
val name: String,
val enabled: Boolean = true,
val actionEffect: ActionEffectTimeline,
val icon: ResourceLocation,
val cooldownTicks: Int,
val accessCondition: ExpressionLike = "true".asExpressionLike(),
val useCondition: ExpressionLike = "true".asExpressionLike(),
// Targeting
val targetType: TargetType? = null,
val range: Double? = null,
val targetCondition: ExpressionLike? = null,
// Granting
val grantingMoves: List<String>? = null,
val grantingAbilities: List<String>? = null,
val grantingTypes: List<String>? = null,
val grantingSpecies: List<String>? = null,
// Wrapper skill fields
val hitDelay: ExpressionLike? = null,
val hitEffect: ResourceLocation? = null,
val fallbackActionEffect: ResourceLocation? = null
) {
// Enum to determine what this skill will target.
enum class TargetType {
NONE, SELF, BLOCK, ENTITY, BOTH
}
companion object {
val runtime = MoLangRuntime().setup()
val CODEC = RecordCodecBuilder.create<PokeSkill> { instance ->
instance.group(
Codec.STRING.fieldOf("name").forGetter { it.name },
Codec.BOOL.fieldOf("enabled").forGetter { it.enabled },
Codec.unit<ActionEffectTimeline> { ActionEffectTimeline.NONE }.fieldOf("actionEffect").forGetter { it.actionEffect },
ResourceLocation.CODEC.fieldOf("icon").forGetter { it.icon },
Codec.INT.fieldOf("cooldownTicks").forGetter { it.cooldownTicks },
EXPRESSION_LIKE_CODEC.fieldOf("accessCondition").forGetter { it.accessCondition },
EXPRESSION_LIKE_CODEC.fieldOf("useCondition").forGetter { it.useCondition }
).apply(instance, ::PokeSkill)
}
val PACKET_CODEC = ByteBufCodecs.fromCodecWithRegistries(CODEC)
private val DEFAULT_ACTION_EFFECT = cobblemonResource("default_poke_skill")
}
@Transient
lateinit var id: ResourceLocation
// fun canAccess(player: Player, pokemon: Pokemon): Boolean {
// if (!enabled) {
// return false
// }
//
// runtime.withQueryValue("player", player.asMostSpecificMoLangValue())
// runtime.withQueryValue("pokemon", pokemon.struct)
// pokemon.entity?.let { runtime.withQueryValue("entity", it.asMostSpecificMoLangValue()) }
// val hasAccess = runtime.resolveBoolean(accessCondition)
// return hasAccess
// }
/**
* Determines access by checking the pokemons data against the granting lists.
* If no granting lists are populated, accessCondition is used as a fallback.
*/
fun canAccess(player: Player, pokemon: Pokemon): Boolean {
if (!enabled) {
return false
}
// Check granting lists — if any are populated, check if the player has any of the listed moves/abilities/types/species
val hasGrantingLists = !grantingMoves.isNullOrEmpty() || !grantingAbilities.isNullOrEmpty() ||
!grantingTypes.isNullOrEmpty() || !grantingSpecies.isNullOrEmpty()
if (hasGrantingLists) {
val moveMatch = !grantingMoves.isNullOrEmpty() && grantingMoves.any { moveName ->
pokemon.moveSet.any { it.template.name == moveName }
}
val abilityMatch = !grantingAbilities.isNullOrEmpty() && grantingAbilities.any { abilityName ->
pokemon.ability.name == abilityName
}
val typeMatch = !grantingTypes.isNullOrEmpty() && grantingTypes.any { typeName ->
pokemon.types.any { it.name.equals(typeName, ignoreCase = true) }
}
val speciesMatch = !grantingSpecies.isNullOrEmpty() && grantingSpecies.any { speciesName ->
pokemon.species.name.equals(speciesName, ignoreCase = true)
}
if (!(moveMatch || abilityMatch || typeMatch || speciesMatch)) return false
}
// Always evaluate accessCondition — acts as additional gate when granting lists are present,
// or as the sole gate when no granting lists are populated
runtime.withQueryValue("player", player.asMostSpecificMoLangValue())
runtime.withQueryValue("pokemon", pokemon.struct)
pokemon.entity?.let { runtime.withQueryValue("entity", it.asMostSpecificMoLangValue()) }
return runtime.resolveBoolean(accessCondition ?: "true".asExpressionLike())
}
fun canUse(player: Player, pokemon: Pokemon): Boolean {
val status = pokemon.status?.status
if (id in pokemon.skillCooldownsTicks || player.isInBattle() || status == Statuses.SLEEP || status == Statuses.FROZEN) {
return false
}
runtime.withQueryValue("player", player.asMostSpecificMoLangValue())
runtime.withQueryValue("pokemon", pokemon.struct)
val canUse = runtime.resolveBoolean(useCondition)
return canUse
}
/**
* Resolves which move from the pokemon's moveset grants this skill.
* Returns the first matching move name from grantingMoves, or null if none match.
*/
fun resolveGrantingMove(pokemon: Pokemon): String? {
if (grantingMoves.isNullOrEmpty()) return null // need this guard
return grantingMoves.firstOrNull { moveName ->
pokemon.moveSet.any { it.template.name == moveName }
}
}
/**
* Resolves the action effect to use for the move visual.
* Priority: granting move's action effect > fallbackActionEffect > null
*/
fun resolveVisualEffect(pokemon: Pokemon): ResourceLocation? {
val grantingMove = resolveGrantingMove(pokemon)
if (grantingMove != null) {
val effectId = cobblemonResource(grantingMove)
if (ActionEffects.actionEffects.containsKey(effectId)) return effectId
Cobblemon.LOGGER.warn("PokeSkill '$id': granting move '$grantingMove' has no action effect at '$effectId'")
}
return fallbackActionEffect
}
/**
* Runs the skill on the given pokemon.
* Populates context and runs targeting logic.
*/
fun use(
player: ServerPlayer,
pokemon: Pokemon,
// context information!!!
): Boolean {
if (!canUse(player, pokemon)) return false
val entity = pokemon.entity ?: return false
val level = player.level() as? ServerLevel ?: return false
// I think these should be defaulted but making them nullable means I don't have to adjust the
// other jsons that don't populate them yet...
val effectiveTargetType = targetType ?: TargetType.NONE
val effectiveRange = range ?: 8.0
// Resolve the action effect to run
val effectTimeline = if (actionEffect != null && actionEffect != ActionEffectTimeline.NONE) {
actionEffect
} else {
ActionEffects.actionEffects[DEFAULT_ACTION_EFFECT] ?: run {
Cobblemon.LOGGER.warn("PokeSkill '$id': default_poke_skill action effect not found")
return false
}
}
// Set up runtime
val skillRuntime = MoLangRuntime().setup()
skillRuntime.withQueryValue("player", player.asMostSpecificMoLangValue())
skillRuntime.withQueryValue("pokemon", pokemon.struct)
skillRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
skillRuntime.environment.setSimpleVariable("skill_id", StringValue(id.toString()))
skillRuntime.environment.setSimpleVariable("target_type", StringValue(effectiveTargetType.name.lowercase()))
skillRuntime.environment.query.addFunction("missed") { DoubleValue(0.0) } // move action effects use this to determine if the target particles should play. We want them to always play for skills I believe
// Targeting — raycast based on targetType
when (effectiveTargetType) {
TargetType.SELF -> {
injectEntityTarget(skillRuntime, player)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(1.0))
}
TargetType.BLOCK -> {
val blockHit = getPlayerLookedBlock(player, effectiveRange)
if (blockHit == null) return false
injectBlockTarget(skillRuntime, blockHit, level)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(0.0))
}
TargetType.ENTITY -> {
val entityHit = getPlayerLookedEntity(player, effectiveRange)
if (entityHit == null) return false
injectEntityTarget(skillRuntime, entityHit)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(1.0))
}
TargetType.BOTH -> {
val entityHit = getPlayerLookedEntity(player, effectiveRange)
if (entityHit != null) {
injectEntityTarget(skillRuntime, entityHit)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(1.0))
} else {
val blockHit = getPlayerLookedBlock(player, effectiveRange)
if (blockHit == null) return false
injectBlockTarget(skillRuntime, blockHit, level)
skillRuntime.environment.setSimpleVariable("target_is_entity", DoubleValue(0.0))
}
}
TargetType.NONE -> {}
}
// Evaluate target condition
if (targetCondition != null && !skillRuntime.resolveBoolean(targetCondition)) return false
// Inject wrapper skill variables
val visualEffect = resolveVisualEffect(pokemon)
if (visualEffect != null) {
skillRuntime.environment.setSimpleVariable("granting_move", StringValue(visualEffect.toString()))
}
if (hitEffect != null) {
skillRuntime.environment.setSimpleVariable("hit_effect", StringValue(hitEffect.toString()))
}
if (hitDelay != null) {
skillRuntime.environment.setSimpleVariable("hit_delay", hitDelay.resolve(skillRuntime))
}
// Build providers
val providers = mutableListOf<Any>(
UsersProvider(entity)
)
// Build and run context
val context = ActionEffectContext(
actionEffect = effectTimeline,
runtime = skillRuntime,
providers = providers,
level = level
)
effectTimeline.run(context).thenRun {
// Auto-apply cooldown after effect completes
pokemon.skillCooldownsTicks[id] = cooldownTicks
}
return true
}
/**
* Utility functions for setting up the runtime for a skill.
*/
private fun injectBlockTarget(runtime: MoLangRuntime, blockHit: BlockHitResult, level: ServerLevel) {
val pos = blockHit.blockPos
runtime.environment.setSimpleVariable("target_x", DoubleValue(pos.x + 0.5))
runtime.environment.setSimpleVariable("target_y", DoubleValue(pos.y + 0.5))
runtime.environment.setSimpleVariable("target_z", DoubleValue(pos.z + 0.5))
runtime.environment.setSimpleVariable("target_block_x", DoubleValue(pos.x.toDouble()))
runtime.environment.setSimpleVariable("target_block_y", DoubleValue(pos.y.toDouble()))
runtime.environment.setSimpleVariable("target_block_z", DoubleValue(pos.z.toDouble()))
val blockState = level.getBlockState(pos)
val blockHolder = level.blockRegistry.wrapAsHolder(blockState.block)
val blockValue = blockHolder.asMoLangValue(Registries.BLOCK)
blockValue.addFunction("x") { DoubleValue(pos.x.toDouble()) }
blockValue.addFunction("y") { DoubleValue(pos.y.toDouble()) }
blockValue.addFunction("z") { DoubleValue(pos.z.toDouble()) }
runtime.environment.setSimpleVariable("target_block", blockValue)
}
private fun injectEntityTarget(runtime: MoLangRuntime, entityHit: Entity) {
runtime.environment.setSimpleVariable("target_x", DoubleValue(entityHit.x))
runtime.environment.setSimpleVariable("target_y", DoubleValue(entityHit.y + entityHit.bbHeight / 2.0))
runtime.environment.setSimpleVariable("target_z", DoubleValue(entityHit.z))
runtime.environment.setSimpleVariable("target_entity", entityHit.asMostSpecificMoLangValue())
}
/**
* simple raycast to get the block the player is looking at.
*/
private fun getPlayerLookedBlock(player: ServerPlayer, range: Double): BlockHitResult? {
val hitResult = player.pick(range, 0f, true)
return if (hitResult.type == HitResult.Type.BLOCK) hitResult as BlockHitResult else null
}
/**
* Raycast to determine the entity the player is looking at
*/
private fun getPlayerLookedEntity(player: ServerPlayer, range: Double): Entity? {
val eyePosition = player.getEyePosition(1.0f)
val lookVector = player.getViewVector(1.0f)
val reachVector = eyePosition.add(lookVector.x * range, lookVector.y * range, lookVector.z * range)
// Create an outer bounding box to find potential candidates
val searchBox = player.boundingBox.expandTowards(lookVector.scale(range)).inflate(1.0, 1.0, 1.0)
// Filter entities within the search box
val entityHitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(
player,
eyePosition,
reachVector,
searchBox,
{ entity -> !entity.isSpectator && entity.isPickable },
range * range
)
return entityHitResult?.entity
}
}
@@ -20,13 +20,12 @@ object ServerTickHandler {
secondsTick++
// Party tick
for (player in server.playerList.players) {
val party = player.party()
party.forEach { it.tickSkillCooldowns() }
if (secondsTick == 20) {
secondsTick = 0
party.onSecondPassed(player)
if (secondsTick == 20) {
secondsTick = 0
// Party tick
for (player in server.playerList.players) {
player.party().onSecondPassed(player)
}
}
}
@@ -1,38 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.data
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.entity.pokemon.PokeSkill
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.RegistryFriendlyByteBuf
class PokeSkillsRegistrySyncPacket(
pokeSkills: Collection<PokeSkill>
) : DataRegistrySyncPacket<PokeSkill, PokeSkillsRegistrySyncPacket>(pokeSkills) {
override val id = ID
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: PokeSkill) {
PokeSkill.PACKET_CODEC.encode(buffer, entry)
}
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): PokeSkill? {
return PokeSkill.PACKET_CODEC.decode(buffer)
}
override fun synchronizeDecoded(entries: Collection<PokeSkill>) {
CobblemonPokeSkills.reload(entries.associateBy { it.id })
}
companion object {
val ID = cobblemonResource("poke_skill_sync")
fun decode(buffer: RegistryFriendlyByteBuf) = PokeSkillsRegistrySyncPacket(emptyList()).apply { decodeBuffer(buffer) }
}
}
@@ -13,15 +13,10 @@ import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHa
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.phys.Vec3
/**
* Packet that spawns a snowstorm particle effect on a specified entity and specified locator.
* Can specify an optional target+locator to pass through to the spawned particle
* Can alternatively specify a [targetPosition] for entity-to-world-position targeting
* (e.g. a Pokémon firing particles at a block).
*
* Target resolution priority: targetedEntityId + targetLocators > targetPosition > no target
*
* Handled by [SpawnSnowstormEntityParticleHandler]
*
@@ -33,8 +28,7 @@ class SpawnSnowstormEntityParticlePacket(
val sourceEntityId: Int,
val sourceLocators: List<String> = listOf("root"),
val targetedEntityId: Int? = null,
val targetLocators: List<String>? = null,
val targetPosition: Vec3? = null
val targetLocators: List<String>? = null
) : NetworkPacket<SpawnSnowstormEntityParticlePacket> {
companion object {
val ID = cobblemonResource("spawn_snowstorm_entity_particle")
@@ -45,8 +39,7 @@ class SpawnSnowstormEntityParticlePacket(
val sourceLocators = buffer.readList { buffer.readString() }
val targetedEntityId = buffer.readNullable { it.readInt() }
val targetLocators = buffer.readNullable { buffer.readList { buffer.readString() }}
val targetPosition = buffer.readNullable { Vec3(it.readDouble(), it.readDouble(), it.readDouble()) }
return SpawnSnowstormEntityParticlePacket(effectId, sourceEntityId, sourceLocators, targetedEntityId, targetLocators, targetPosition)
return SpawnSnowstormEntityParticlePacket(effectId, sourceEntityId, sourceLocators, targetedEntityId, targetLocators)
}
}
@@ -62,10 +55,5 @@ class SpawnSnowstormEntityParticlePacket(
buffer.writeString(locator)
}
}
buffer.writeNullable(targetPosition) { _, value ->
buffer.writeDouble(value.x)
buffer.writeDouble(value.y)
buffer.writeDouble(value.z)
}
}
}
@@ -1,51 +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.pokemon.update
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readSizedInt
import com.cobblemon.mod.common.util.writeSizedInt
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* Packet that adds a single skill cooldown to a Pokémon's skill cooldowns map.
*
* @author Hiroku
* @since August 31st, 2025
*/
class SkillCooldownsUpdatePacket(
pokemon: () -> Pokemon?,
val skillId: ResourceLocation,
val cooldownTicks: Int
) : SingleUpdatePacket<Pair<ResourceLocation, Int>, SkillCooldownsUpdatePacket>(pokemon, skillId to cooldownTicks) {
override val id: ResourceLocation = ID
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(skillId)
buffer.writeSizedInt(IntSize.U_SHORT, cooldownTicks)
}
override fun set(pokemon: Pokemon, value: Pair<ResourceLocation, Int>) {
val (skillId, cooldownTicks) = value
pokemon.skillCooldownsTicks[skillId] = cooldownTicks
}
companion object {
val ID = cobblemonResource("skill_cooldowns_update")
fun decode(buffer: RegistryFriendlyByteBuf): SkillCooldownsUpdatePacket {
val pokemon = decodePokemon(buffer)
val skillId = buffer.readResourceLocation()
val cooldownTicks = buffer.readSizedInt(IntSize.U_SHORT)
return SkillCooldownsUpdatePacket(pokemon, skillId, cooldownTicks)
}
}
}
@@ -26,9 +26,7 @@ class ServerSettingsPacket internal constructor(
val maxPokemonLevel: Int,
val maxPokemonFriendship: Int,
val maxDynamaxLevel: Int,
val unlockAllMoveDexMovesByDefault: Boolean,
val pokemonIntrinsicSizeMin: Float,
val pokemonIntrinsicSizeMax: Float
val unlockAllMoveDexMovesByDefault: Boolean
) : NetworkPacket<ServerSettingsPacket> {
override val id = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
@@ -39,14 +37,9 @@ class ServerSettingsPacket internal constructor(
buffer.writeInt(Cobblemon.config.maxPokemonFriendship)
buffer.writeInt(Cobblemon.config.maxDynamaxLevel)
buffer.writeBoolean(Cobblemon.config.unlockAllMoveDexMovesByDefault)
buffer.writeFloat(Cobblemon.config.pokemonIntrinsicSizeMin)
buffer.writeFloat(Cobblemon.config.pokemonIntrinsicSizeMax)
}
companion object {
val ID = cobblemonResource("server_settings")
fun decode(buffer: RegistryFriendlyByteBuf) = ServerSettingsPacket(buffer.readBoolean(),
buffer.readBoolean(), buffer.readBoolean(),
buffer.readInt(), buffer.readInt(), buffer.readInt(),
buffer.readBoolean(), buffer.readFloat(), buffer.readFloat())
fun decode(buffer: RegistryFriendlyByteBuf) = ServerSettingsPacket(buffer.readBoolean(), buffer.readBoolean(), buffer.readBoolean(), buffer.readInt(), buffer.readInt(), buffer.readInt(), buffer.readBoolean())
}
}
@@ -1,47 +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
import com.cobblemon.mod.common.api.net.NetworkPacket
import java.util.UUID
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* Packet sent by the client to the server to indicate that it wants to use a Poké Skill.
*
* The server will validate if the skill can be used, and if so, will execute it.
*
* @param skillId The ID of the skill to use.
* @param pokemonId The UUID of the Pokémon using the skill.
*
* @author Hiroku
* @since August 31st, 2025
*/
class UsePokeSkillPacket(
val skillId: ResourceLocation,
val pokemonId: UUID,
) : NetworkPacket<UsePokeSkillPacket> {
override val id: ResourceLocation = ID
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeResourceLocation(skillId)
buffer.writeUUID(pokemonId)
}
companion object {
val ID = ResourceLocation("cobblemon", "use_poke_skill")
fun decode(buffer: RegistryFriendlyByteBuf): UsePokeSkillPacket {
return UsePokeSkillPacket(
buffer.readResourceLocation(),
buffer.readUUID()
)
}
}
}
@@ -1,27 +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
import com.cobblemon.mod.common.CobblemonPokeSkills
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.server.UsePokeSkillPacket
import com.cobblemon.mod.common.util.party
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ServerPlayer
object UsePokeSkillHandler : ServerNetworkPacketHandler<UsePokeSkillPacket> {
override fun handle(packet: UsePokeSkillPacket, server: MinecraftServer, player: ServerPlayer) {
val party = player.party()
val pokemon = party[packet.pokemonId] ?: return // Who?
val skill = CobblemonPokeSkills.getAccessibleSkills(player, pokemon).firstOrNull { it.id == packet.skillId } ?: return // What skill?
if (skill.canUse(player, pokemon)) {
skill.use(player, pokemon)
}
}
}
@@ -767,8 +767,6 @@ open class Pokemon : ShowdownIdentifiable {
val riding: RidingProperties
get() = this.form.riding
var skillCooldownsTicks: MutableMap<ResourceLocation, Int> = mutableMapOf()
init {
storeCoordinates.subscribe { if (it != null && it.store !is PCStore && this.tetheringId != null) afterOnServer(seconds = 0.05F) { this.tetheringId = null } }
storeCoordinates.subscribe {
@@ -1143,16 +1141,6 @@ open class Pokemon : ShowdownIdentifiable {
}
}
fun tickSkillCooldowns() {
this.skillCooldownsTicks.entries.forEach { (key, value) ->
val newValue = value - 1
if (newValue <= 0)
this.skillCooldownsTicks -= key
else
this.skillCooldownsTicks[key] = newValue
}
}
fun isOnInteractionCooldown(group: ResourceLocation): Boolean {
return this.interactionCooldowns.getOrDefault(group, 0) > 0
}
@@ -2241,11 +2229,6 @@ open class Pokemon : ShowdownIdentifiable {
return true
}
fun addSkillCooldown(skillId: ResourceLocation, cooldownTicks: Int) {
skillCooldownsTicks[skillId] = cooldownTicks
onChange(SkillCooldownsUpdatePacket({ this }, skillId, cooldownTicks))
}
fun notify(packet: PokemonUpdatePacket<*>) {
storeCoordinates.get()?.run { sendPacketToPlayers(store.getObservingPlayers(), packet) }
}
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.pokemon
import com.cobblemon.mod.common.client.settings.ServerSettings
import com.cobblemon.mod.common.Cobblemon
enum class PokemonSizeCategory {
XS,
@@ -21,7 +21,7 @@ enum class PokemonSizeCategory {
// Find which size category corresponds to the given scale modifier.
// The scale modifier should be between the intrinsic min and max size.
fun fromScale(scaleModifier: Float): PokemonSizeCategory {
val config = ServerSettings //Don't use cobblemon config here as it will be used by server AND client
val config = Cobblemon.config
val minScale = config.pokemonIntrinsicSizeMin
val maxScale = config.pokemonIntrinsicSizeMax
val range = (maxScale - minScale).coerceAtLeast(0.0001F)
@@ -318,7 +318,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
// Hitbox thing looks confusing but if the hitbox volume is more than like, 5, it starts getting pretty
// fucking slow to use the findAcceptedNodeWalk function
val strictlyWalkPathing = !canFly() && !mob.isInWater
val strictlyWalkPathing = !canFly() && !mob.isInWater && mob.boundingBox.size < MAX_HITBOX_SIZE_FOR_WALKING
val doVerticalNeighbourChecks = (canFly() || mob.isInWater) && mob.boundingBox.size < MAX_HITBOX_FOR_VERTICAL_NEIGHBOURS
// Non-diagonal surroundings in 3d space
@@ -623,11 +623,9 @@ class OmniPathNodeMaker : NodeEvaluator() {
override fun getPathTypeOfMob(pfContext: PathfindingContext, x: Int, y: Int, z: Int, mob: Mob): PathType {
val set = EnumSet.noneOf(PathType::class.java)
// Capping the observed size of hitboxes here to put an upper limit on the cost of larger hitbox mobs
// Mobs larger than these caps will inevitably become stuck on obstacles as their pathing will be flawed
val sizeX = ((mob.boundingBox.maxX - mob.boundingBox.minX).toInt() + 1).coerceAtMost(2)
val sizeY = ((mob.boundingBox.maxY - mob.boundingBox.minY).toInt() + 1).coerceAtMost(3)
val sizeZ = ((mob.boundingBox.maxZ - mob.boundingBox.minZ).toInt() + 1).coerceAtMost(2)
val sizeX = (mob.boundingBox.maxX - mob.boundingBox.minX).toInt() + 1
val sizeY = (mob.boundingBox.maxY - mob.boundingBox.minY).toInt() + 1
val sizeZ = (mob.boundingBox.maxZ - mob.boundingBox.minZ).toInt() + 1
// TODO -- This is experimental code to see if this is meaningful. We should clean this up later when time permits.
val returnedEarlyPathType = mutableListOf<PathType>()
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.pokemon.status.statuses.persistent
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.util.cobblemonResource
class FrozenStatus : PersistentStatus(
name = cobblemonResource("frozen"),
showdownName = "frz",
@@ -20,7 +20,6 @@ object DataKeys {
const val POKEMON_FRIENDSHIP = "Friendship"
const val POKEMON_FULLNESS = "Fullness"
const val POKEMON_INTERACTION_COOLDOWN = "InteractionCooldown"
const val POKEMON_SKILL_COOLDOWNS = "SkillCooldowns"
const val POKEMON_ALPHA = "Alpha"
const val POKEMON_IVS = "IVs"
@@ -100,16 +100,10 @@ fun ServerPlayer.didSleep(): Boolean {
return true
}
fun Player.isInBattle() = if (this is ServerPlayer) {
BattleRegistry.getBattleByParticipatingPlayer(this) != null
} else {
CobblemonClient.battle?.spectating == false
}
fun ServerPlayer.isInBattle() = BattleRegistry.getBattleByParticipatingPlayer(this) != null
var ServerPlayer.spawner: PlayerSpawner
get() = (this as PlayerSpawnerAccessor).getPlayerSpawner()
set(value) = (this as PlayerSpawnerAccessor).setPlayerSpawner(value)
fun ServerPlayer.getBattleState(): Pair<PokemonBattle, BattleActor>? {
val battle = BattleRegistry.getBattleByParticipatingPlayer(this)
if (battle != null) {
@@ -1,31 +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.util.adapters
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import java.lang.reflect.Type
/**
* Adapter for deserializing a reference to an [ActionEffectTimeline] from its identifier.
*
* @author Hiroku
* @since August 31st, 2025
*/
object ActionEffectTimelineAdapter : JsonDeserializer<ActionEffectTimeline> {
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): ActionEffectTimeline {
val identifier = json.asString.asIdentifierDefaultingNamespace()
val timeline = ActionEffects.actionEffects[identifier]
return timeline ?: throw IllegalArgumentException("No ActionEffectTimeline found for id $identifier")
}
}
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.util.codec
import com.bedrockk.molang.Expression
import com.bedrockk.molang.MoLang
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.getString
import com.mojang.serialization.Codec
import com.mojang.serialization.Codec.optionalField
@@ -31,17 +29,6 @@ val EXPRESSION_CODEC = object : PrimitiveCodec<Expression> {
}
}
val EXPRESSION_LIKE_CODEC = object : PrimitiveCodec<ExpressionLike> {
override fun <T> read(ops: DynamicOps<T>, input: T): DataResult<ExpressionLike> {
return ops.getStringValue(input).map { it.asExpressionLike() }
}
override fun <T> write(ops: DynamicOps<T>, value: ExpressionLike): T {
return ops.createString(value.getString())
}
}
// special codec that always writes default value
// vanilla changed the behaviour of Codec#optionalFieldOf(String, A) so that it OMITS default values when encoding
// later on decoding it assumes no value -> default, but we want some default being encoded anyways so it can be targeted by commands
@@ -22,12 +22,10 @@ import net.minecraft.world.item.ItemStack
import java.util.*
internal data class ClientPokemonP4(
val skillCooldownTicks: Map<ResourceLocation, Int>,
val originalTrainerFriendship: Optional<Int>,
val originalTrainerFriendship: Optional<Int>
) : Partial<Pokemon> {
override fun into(other: Pokemon): Pokemon {
other.skillCooldownsTicks = this.skillCooldownTicks.toMutableMap()
this.originalTrainerFriendship.ifPresent { other.originalTrainerFriendship = it }
return other
}
@@ -38,13 +36,11 @@ internal data class ClientPokemonP4(
*/
internal val CODEC: MapCodec<ClientPokemonP4> = RecordCodecBuilder.mapCodec { instance ->
instance.group(
Codec.unboundedMap(ResourceLocation.CODEC, Codec.INT).fieldOf(DataKeys.POKEMON_SKILL_COOLDOWNS).forGetter(ClientPokemonP4::skillCooldownTicks),
Codec.INT.optionalFieldOf(DataKeys.POKEMON_ORIGINAL_TRAINER_FRIENDSHIP).forGetter(ClientPokemonP4::originalTrainerFriendship),
).apply(instance, ::ClientPokemonP4)
Codec.INT.optionalFieldOf(DataKeys.POKEMON_ORIGINAL_TRAINER_FRIENDSHIP).forGetter(ClientPokemonP4::originalTrainerFriendship)
).apply(instance, ::ClientPokemonP4)
}
internal fun from(pokemon: Pokemon): ClientPokemonP4 = ClientPokemonP4(
pokemon.skillCooldownsTicks,
Optional.ofNullable(pokemon.originalTrainerFriendship)
)
}
@@ -13,16 +13,13 @@ import com.cobblemon.mod.common.util.DataKeys
import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.resources.ResourceLocation
import java.util.*
internal data class PokemonP4(
val skillCooldownTicks: Map<ResourceLocation, Int>,
val originalTrainerFriendship: Optional<Int>,
val originalTrainerFriendship: Optional<Int>
) : Partial<Pokemon> {
override fun into(other: Pokemon): Pokemon {
other.skillCooldownsTicks = this.skillCooldownTicks.toMutableMap()
this.originalTrainerFriendship.ifPresent { other.originalTrainerFriendship = it }
other.refreshOriginalTrainer()
return other
@@ -31,20 +28,16 @@ internal data class PokemonP4(
companion object {
internal val CODEC: MapCodec<PokemonP4> = RecordCodecBuilder.mapCodec { instance ->
instance.group(
Codec.unboundedMap(ResourceLocation.CODEC, Codec.INT).optionalFieldOf(DataKeys.POKEMON_SKILL_COOLDOWNS, emptyMap<ResourceLocation, Int>()).forGetter { it.skillCooldownTicks },
Codec.INT.optionalFieldOf(DataKeys.POKEMON_ORIGINAL_TRAINER_FRIENDSHIP).forGetter(PokemonP4::originalTrainerFriendship),
Codec.INT.optionalFieldOf(DataKeys.POKEMON_ORIGINAL_TRAINER_FRIENDSHIP).forGetter(PokemonP4::originalTrainerFriendship)
).apply(instance) {
skillCooldownTicks,
originalTrainerFriendship -> PokemonP4(
skillCooldownTicks,
originalTrainerFriendship,
originalTrainerFriendship
)
}
}
internal fun from(pokemon: Pokemon): PokemonP4 = PokemonP4(
pokemon.skillCooldownsTicks,
Optional.ofNullable(pokemon.originalTrainerFriendship),
Optional.ofNullable(pokemon.originalTrainerFriendship)
)
}
}
@@ -96,6 +96,458 @@
}
}
},
"animation.poliwrath.ground_walk": {
"loop": true,
"animation_length": 1.3333,
"bones": {
"waist": {
"rotation": ["9 - math.sin( q.anim_time * 90 * 6 - 45)*-4", "-math.sin( q.anim_time * 90 * 3)*8", "math.sin( q.anim_time * 90 * 3)*4"],
"position": [0, "-0.3+math.sin( q.anim_time * 90 * 6)*1.5", 0]
},
"torso": {
"rotation": ["8 - math.sin( q.anim_time * 90 * 6 - 45)*8", "-math.sin( q.anim_time * 90 * 3 - 25)*-8", "math.sin( q.anim_time * 90 * 3 - 25)*-8"],
"position": [0, "math.sin( q.anim_time * 90 * 6 + 45)*0.3", 0]
},
"head": {
"rotation": ["-math.sin( q.anim_time * 90 * 6 - 45)*-4", "-math.sin( q.anim_time * 90 * 3 - 25)*-1", 0]
},
"arm_left1": {
"rotation": {
"0.0": {
"post": [-13.63, -16.48493, 36.18],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [-41, 8.77773, 38.5],
"lerp_mode": "catmullrom"
},
"0.625": {
"post": [-8.15, -36.46773, 42.45],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [24.5, -46.5535, 23.9],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [-13.63, -16.48493, 36.18],
"lerp_mode": "catmullrom"
}
}
},
"arm_left2": {
"rotation": {
"0.0": {
"post": [0, 61.31326, 0],
"lerp_mode": "catmullrom"
},
"0.2917": {
"post": [0, 70.51, 0],
"lerp_mode": "catmullrom"
},
"0.5833": {
"post": [0, 45.6917, 0],
"lerp_mode": "catmullrom"
},
"0.875": {
"post": [0, 32.9252, 0],
"lerp_mode": "catmullrom"
},
"1.125": {
"post": [0, 33.79, 0],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [0, 61.31326, 0],
"lerp_mode": "catmullrom"
}
}
},
"hand_left": {
"rotation": {
"0.0": {
"post": [-6.39933, 10.3524, 6.73624],
"lerp_mode": "catmullrom"
},
"0.375": {
"post": [-6.4, 10.35, 6.74],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [-6.39933, 10.3524, 6.73624],
"lerp_mode": "catmullrom"
}
}
},
"finger_front_left1": {
"rotation": {
"0.0": {
"post": [0, 0, 67.5],
"lerp_mode": "catmullrom"
}
}
},
"finger_front_left2": {
"rotation": {
"0.0": {
"post": [0, 0, 67.5],
"lerp_mode": "catmullrom"
}
}
},
"finger_back_left1": {
"rotation": [0, 0, 70]
},
"finger_back_left2": {
"rotation": [0, 0, 72.5]
},
"thumb_left1": {
"rotation": [35.65498, -41.23664, 27.4926]
},
"arm_right1": {
"rotation": {
"0.0": {
"post": [-8.15, 36.46773, -42.45],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [24.5, 46.5535, -23.9],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [-13.63, 16.48493, -36.18],
"lerp_mode": "catmullrom"
},
"0.9167": {
"post": [-41, -8.77773, -38.5],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [-8.15, 36.46773, -42.45],
"lerp_mode": "catmullrom"
}
}
},
"arm_right2": {
"rotation": {
"0.0": {
"post": [0, -45.6917, 0],
"lerp_mode": "catmullrom"
},
"0.2083": {
"post": [0, -32.9252, 0],
"lerp_mode": "catmullrom"
},
"0.4583": {
"post": [0, -33.79, 0],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [0, -61.31326, 0],
"lerp_mode": "catmullrom"
},
"0.9583": {
"post": [0, -70.51, 0],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [0, -45.6917, 0],
"lerp_mode": "catmullrom"
}
}
},
"hand_right": {
"rotation": {
"0.0": {
"post": [-6.4, -10.35, -6.74],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [-6.39933, -10.3524, -6.73624],
"lerp_mode": "catmullrom"
},
"1.0417": {
"post": [-6.4, -10.35, -6.74],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [-6.4, -10.35, -6.74],
"lerp_mode": "catmullrom"
}
}
},
"finger_front_right1": {
"rotation": {
"0.0": {
"post": [0, 0, -67.5],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [0, 0, -67.5],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [0, 0, -67.5],
"lerp_mode": "catmullrom"
}
}
},
"finger_front_right2": {
"rotation": {
"0.0": {
"post": [0, 0, -67.5],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [0, 0, -67.5],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [0, 0, -67.5],
"lerp_mode": "catmullrom"
}
}
},
"finger_back_right1": {
"rotation": {
"0.0": [0, 0, -70],
"0.6667": [0, 0, -70],
"1.3333": [0, 0, -70]
}
},
"finger_back_right2": {
"rotation": {
"0.0": [0, 0, -72.5],
"0.6667": [0, 0, -72.5],
"1.3333": [0, 0, -72.5]
}
},
"leg_left": {
"rotation": {
"0.0": [-3.5, 0, 0],
"0.25": [28, 0, 0],
"0.3333": [27, 0, 0],
"0.4583": [36, 0, 0],
"0.6667": {
"pre": [-1, 0, 0],
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
},
"0.8333": {
"post": [-57.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0833": [-35, 0, 0],
"1.3333": [-3.5, 0, 0]
},
"position": {
"0.0": [0, -0.3, 0],
"0.25": [0, -1.1, 2.3],
"0.3333": [0, 0.25, 2.3],
"0.4583": [0, 0.2, 1.8],
"0.6667": {
"pre": [0, 0.9, -0.4],
"post": [0, 0.9, -0.4],
"lerp_mode": "catmullrom"
},
"0.8333": {
"post": [0, 0.8, -2.3],
"lerp_mode": "catmullrom"
},
"1.0": [0, -0.7, -2.3],
"1.0833": [0, -1.3, -2.3],
"1.3333": [0, -0.3, 0]
}
},
"leg_left2": {
"rotation": {
"0.0": [9, 0, 0],
"0.25": [5, 0, 0],
"0.3333": [14, 0, 0],
"0.4583": [33, 0, 0],
"0.5417": {
"pre": [57.7, 0, 0],
"post": [57.7, 0, 0],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [53, 0, 0],
"lerp_mode": "catmullrom"
},
"0.8333": {
"post": [34.5, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0": [17, 0, 0],
"1.0833": [13, 0, 0],
"1.3333": [9, 0, 0]
}
},
"foot_left": {
"rotation": {
"0.0": [-5, 0, 0],
"0.25": [-32, 0, 0],
"0.3333": [1.5, 0, 0],
"0.5": {
"pre": [29, 0, 0],
"post": [29, 0, 0],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0": [-13, 0, 0],
"1.0833": [22, 0, 0],
"1.3333": [-5, 0, 0]
}
},
"toes_left": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [0, 0, 0],
"0.3333": [-41, 0, 0],
"0.5": {
"pre": [-19, 0, 0],
"post": [-19, 0, 0],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.875": {
"post": [-23.89, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0417": {
"post": [-20.18, 0, 0],
"lerp_mode": "catmullrom"
},
"1.0833": [0, 0, 0],
"1.3333": [0, 0, 0]
}
},
"leg_right": {
"rotation": {
"0.0": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [-57.5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.4167": [-35, 0, 0],
"0.6667": [-3.5, 0, 0],
"0.9167": [28, 0, 0],
"1.0": [27, 0, 0],
"1.125": [36, 0, 0],
"1.3333": {
"pre": [-1, 0, 0],
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
}
},
"position": {
"0.0": {
"post": [0, 0.9, -0.4],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [0, 0.8, -2.3],
"lerp_mode": "catmullrom"
},
"0.3333": [0, -0.7, -2.3],
"0.4167": [0, -1.3, -2.3],
"0.6667": [0, -0.3, 0],
"0.9167": [0, -1.1, 2.3],
"1.0": [0, 0.25, 2.3],
"1.125": [0, 0.2, 1.8],
"1.3333": {
"pre": [0, 0.9, -0.4],
"post": [0, 0.9, -0.4],
"lerp_mode": "catmullrom"
}
}
},
"leg_right2": {
"rotation": {
"0.0": {
"post": [53, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [34.5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.3333": [17, 0, 0],
"0.4167": [13, 0, 0],
"0.9167": [5, 0, 0],
"1.0": [-1, 0, 0],
"1.125": [33, 0, 0],
"1.2083": {
"pre": [57.7, 0, 0],
"post": [57.7, 0, 0],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [53, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"foot_right": {
"rotation": {
"0.0": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
},
"0.3333": [-13, 0, 0],
"0.4167": [22, 0, 0],
"0.9167": [-32, 0, 0],
"1.0": [-6, 0, 0],
"1.1667": {
"pre": [29, 0, 0],
"post": [29, 0, 0],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [-1, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"toes_right": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.2083": {
"post": [-23.89, 0, 0],
"lerp_mode": "catmullrom"
},
"0.375": {
"post": [-20.18, 0, 0],
"lerp_mode": "catmullrom"
},
"0.4167": [0, 0, 0],
"0.9167": [0, 0, 0],
"1.0": [-41, 0, 0],
"1.1667": {
"pre": [-19, 0, 0],
"post": [-19, 0, 0],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
}
}
},
"animation.poliwrath.battle_idle": {
"loop": true,
"bones": {
@@ -38,6 +38,496 @@
}
}
},
"animation.staryu.physical": {
"loop": true,
"animation_length": 3,
"bones": {
"body": {
"rotation": {
"0.0": {
"post": [0.2, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [12.8384, 24.0851, -4.3796],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [17.8384, 24.0851, -4.3796],
"lerp_mode": "catmullrom"
},
"0.5417": [-90, 0, 0],
"0.7917": [-90, 0, 0],
"0.8333": [-90, 0, 0],
"0.875": {"pre": [-90, 0, 0], "post": [-90, 360, 0]},
"1.1667": [-90, 360, 0],
"1.25": {
"pre": [0, 277.5, 0],
"post": [0, 277.5, 0],
"lerp_mode": "catmullrom"
},
"1.4167": {
"post": [6.39, 117.88, 0],
"lerp_mode": "catmullrom"
},
"2.0": {
"post": [5.48, -33.58, 0],
"lerp_mode": "catmullrom"
},
"2.2083": {
"post": [21.1183, -47.3658, -26.7217],
"lerp_mode": "catmullrom"
},
"2.5417": {
"post": [0, 15, 0],
"lerp_mode": "catmullrom"
},
"3.0": {
"post": [0.2, 0, 0],
"lerp_mode": "catmullrom"
}
},
"position": {
"0.0": {
"post": [0, 0.18, 0],
"lerp_mode": "catmullrom"
},
"0.2083": {
"post": [0, -0.82, -1],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [0, -0.82, -1.4],
"lerp_mode": "catmullrom"
},
"0.5": {
"post": [6.02, 0.94, 0.77],
"lerp_mode": "catmullrom"
},
"0.5833": {
"post": [13.15, -0.88, 3.58],
"lerp_mode": "catmullrom"
},
"0.625": {
"post": [15, -3, 5.6],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [14.57, -5.35, 6.54],
"lerp_mode": "catmullrom"
},
"0.75": {
"post": [13.35, -3.68, 8.94],
"lerp_mode": "catmullrom"
},
"0.8333": {
"post": [11.93, -5.63, 11.86],
"lerp_mode": "catmullrom"
},
"0.875": {
"post": [11.18, -5.08, 13.37],
"lerp_mode": "catmullrom"
},
"0.9583": {
"post": [7, -6, 14.6],
"lerp_mode": "catmullrom"
},
"1.0417": {
"post": [-6.26, -6.52, 13.55],
"lerp_mode": "catmullrom"
},
"1.125": {
"post": [-15, -6, 1.6],
"lerp_mode": "catmullrom"
},
"1.25": [1, 1.4, -20.4],
"1.2917": [0.43, 1.45, -20.36],
"1.3333": [-1.24, 1.49, -21.13],
"1.375": [-1.88, 1.68, -22.94],
"1.4167": [-1.54, 1.81, -24.12],
"1.5417": [-0.88, 1.67, -23.04],
"1.625": [-1.19, 1.92, -22.77],
"1.75": [-2.72, 1.42, -23.27],
"1.9167": [-3.9, 0.72, -26.2],
"2.0": [-3.13, -0.04, -27.22],
"2.125": {
"pre": [-2.63, -1.14, -29.12],
"post": [-2.63, -1.14, -29.12],
"lerp_mode": "catmullrom"
},
"2.2083": {
"post": [-2.2, 5.12, -21.92],
"lerp_mode": "catmullrom"
},
"2.3333": {
"post": [-1.31, 8.05, -13.11],
"lerp_mode": "catmullrom"
},
"2.4583": {
"post": [-0.45, 6.18, -4.51],
"lerp_mode": "catmullrom"
},
"2.5417": {
"post": [0, 0.18, 0],
"lerp_mode": "catmullrom"
},
"2.7083": {
"post": [0.03, -1.22, 0.37],
"lerp_mode": "catmullrom"
},
"3.0": {
"post": [0, 0.18, 0],
"lerp_mode": "catmullrom"
}
}
},
"body_limb_left3": {
"rotation": {
"0.0": [0, 2.5, 0],
"3.0": [0, 2.5, 0]
}
},
"body_limb_bottom_left3": {
"rotation": {
"0.0": [-5, 0, 0],
"3.0": [-5, 0, 0]
}
},
"body_limb_top3": {
"rotation": {
"0.0": [2.5, 0, 0],
"3.0": [2.5, 0, 0]
}
},
"body_limb_left": {
"rotation": {
"0.0": {
"post": [0, 0, 7.5],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [0, 0, 7.5],
"lerp_mode": "catmullrom"
},
"1.375": {
"post": [-10, -20, 20],
"lerp_mode": "catmullrom"
},
"1.875": {
"post": [0, 0, 7.5],
"lerp_mode": "catmullrom"
},
"2.0": {
"post": [5.1686, 19.3385, 5.9149],
"lerp_mode": "catmullrom"
},
"2.125": {
"post": [4.7679, 3.7657, 12.0388],
"lerp_mode": "catmullrom"
},
"2.1667": {
"post": [0, 5, 15],
"lerp_mode": "catmullrom"
},
"3.0": {
"post": [0, 0, 7.5],
"lerp_mode": "catmullrom"
}
},
"scale": {
"2.125": [1, 1, 1],
"2.1667": [1.2, 0.9, 1],
"2.2083": [1, 1, 1]
}
},
"body_limb_bottom_left": {
"rotation": {
"0.0": [0.3, 0, 2.15],
"2.5833": [8.66217, -7.5105, 6.41838],
"2.7083": [-2.3895, -8.7088, 4.394],
"3.0": [0.3, 0, 2.15]
}
},
"body_limb_right": {
"rotation": {
"0.0": {
"post": [0, 0, -7.5],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [0, 0, -7.5],
"lerp_mode": "catmullrom"
},
"1.3333": {
"post": [0, -15, -7.5],
"lerp_mode": "catmullrom"
},
"1.8333": {
"post": [0, 0, -7.5],
"lerp_mode": "catmullrom"
},
"3.0": {
"post": [0, 0, -7.5],
"lerp_mode": "catmullrom"
}
}
},
"body_limb_bottom_right": {
"rotation": {
"0.0": {
"post": [0.3, 0, -2.15],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [-12.5699, -2.2333, 16.2155],
"lerp_mode": "catmullrom"
},
"0.3333": {
"post": [-17.0419, 2.0337, 17.6707],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [-11.9836, 2.1592, 17.6561],
"lerp_mode": "catmullrom"
},
"0.4583": {
"post": [0.2897, -0.0776, 12.85],
"lerp_mode": "catmullrom"
},
"0.5833": {
"post": [0.3, 0, -2.15],
"lerp_mode": "catmullrom"
},
"2.5833": [-9.7324, -5.0125, 8.4786],
"2.7083": [-21.5994, 2.9166, 17.3467],
"3.0": {
"pre": [0.3, 0, -2.15],
"post": [0.3, 0, -2.15],
"lerp_mode": "catmullrom"
}
},
"scale": {
"0.4167": [1, 1, 1],
"0.4583": [1, 1.1, 1],
"0.5": [1, 1, 1]
}
},
"body_limb_bottom_right3": {
"rotation": {
"0.0": [-5, 0, 0],
"3.0": [-5, 0, 0]
}
},
"body_limb_top": {
"rotation": {
"0.0": [0, 0, 0],
"3.0": [0, 0, 0]
}
},
"face": {
"rotation": {
"0.0": [0, 0, 0],
"2.5833": [0, 0, 0],
"2.7083": [0, -7.5, 0],
"2.875": [0, 0, 0]
}
},
"body_limb_top2": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.2083": {
"post": [-7.5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [12.5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.5417": {
"post": [-12.5, 0, 0],
"lerp_mode": "catmullrom"
},
"0.6667": {
"post": [0, 0, 5],
"lerp_mode": "catmullrom"
},
"1.1667": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"body_limb_left2": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [0, -12.5, 0],
"lerp_mode": "catmullrom"
},
"0.2917": {
"post": [-0.0298, 17.7172, 0.0411],
"lerp_mode": "catmullrom"
},
"0.5": {
"post": [-0.1175, -19.5709, 0.2845],
"lerp_mode": "catmullrom"
},
"0.7083": {
"post": [0, 0, 12.5],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [0, 0, 12.5],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [-0.0112, -22.4314, 11.7901],
"lerp_mode": "catmullrom"
},
"1.375": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"2.0": [0, 0, 0],
"2.0833": [13.4251, -35.9563, -26.0018],
"2.125": [17.7735, -35.6335, -34.2819],
"2.1667": [0, 0, 0]
}
},
"body_limb_right2": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.1667": {
"post": [0, 12.5, 0],
"lerp_mode": "catmullrom"
},
"0.2917": {
"post": [-0.0298, -17.7172, -0.0411],
"lerp_mode": "catmullrom"
},
"0.5": {
"post": [-0.1175, 19.5709, -0.2845],
"lerp_mode": "catmullrom"
},
"0.7083": {
"post": [0, 0, 12.5],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [0, 0, 12.5],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [-0.0112, 22.4314, 11.7901],
"lerp_mode": "catmullrom"
},
"1.375": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"body_limb_bottom_left2": {
"rotation": {
"0.0": [0, 0, 0],
"2.5833": [0, 0, 0],
"2.7083": [42.9952, 6.5597, 2.4923],
"3.0": [0, 0, 0]
}
},
"body_limb_bottom_right2": {
"rotation": {
"0.0": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.25": {
"post": [-18.586, -7.5206, -21.2677],
"lerp_mode": "catmullrom"
},
"0.4167": {
"post": [-22.8925, -9.0864, -26.0667],
"lerp_mode": "catmullrom"
},
"0.4583": {
"post": [20.9813, -9.8466, 17.4953],
"lerp_mode": "catmullrom"
},
"0.5833": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"0.75": {
"post": [0, 0, -10],
"lerp_mode": "catmullrom"
},
"1.0833": {
"post": [0, 0, -10],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [29.7624, 0.4222, -0.417],
"lerp_mode": "catmullrom"
},
"1.8333": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"2.25": {
"post": [-13.6038, -3.6461, -10.334],
"lerp_mode": "catmullrom"
},
"2.4583": [-8.1623, 0.0203, 12.7371],
"2.5833": [0, 0, 0],
"2.7083": [35.3924, 9.0867, -26.0666],
"3.0": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
}
},
"torso": {
"rotation": {
"0.0": [0, 0, 0],
"0.25": [0, 0, 0],
"0.2917": [0, 0, 0],
"0.3333": {"pre": [0, 0, 0], "post": [0, 0, 1080]},
"0.4167": [0, 0, 1080],
"0.875": {
"pre": [0, 0, 780],
"post": [0, 0, 780],
"lerp_mode": "catmullrom"
},
"1.25": [0, 0, 201],
"1.8333": [0, 0, 153.14],
"2.0833": {
"pre": [0, 0, 148.3],
"post": [0, 0, 148.3],
"lerp_mode": "catmullrom"
},
"2.2917": {
"post": [0, 0, 153.14],
"lerp_mode": "catmullrom"
},
"2.5": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"3.0": [0, 0, 0]
}
}
}
},
"animation.staryu.ground_walk": {
"loop": true,
"animation_length": 1.6,
@@ -281,7 +281,7 @@
},
"animation.luvdisc.ground_faint": {
"loop": true,
"animation_length": 2.5,
"animation_length": 3,
"bones": {
"body": {
"rotation": {
@@ -55,7 +55,7 @@
{
"name": "torso",
"parent": "body",
"pivot": [0, 8, 0.75],
"pivot": [0, 8, -0.25],
"cubes": [
{"origin": [-5.5, 4.5, -6.5], "size": [11, 9, 12], "uv": [1, 1]}
]
@@ -63,7 +63,7 @@
{
"name": "upper_torso",
"parent": "torso",
"pivot": [0, 12.5, 1.75],
"pivot": [0, 12.5, 0.75],
"cubes": [
{"origin": [-4.5, 12, -5.25], "size": [9, 5, 10], "uv": [2, 24]}
]
@@ -134,12 +134,12 @@
{
"name": "nose",
"parent": "head_angle",
"pivot": [0.5, 24.55, -4.75],
"pivot": [0, 27.25, -4.75],
"rotation": [17.5, 0, 0],
"cubes": [
{"origin": [-1.5, 23.76, -8.005], "size": [3, 1, 4], "inflate": 0.01, "uv": [65, 28]},
{"origin": [-1.5, 24.78, -6.005], "size": [3, 1, 3], "inflate": 0.01, "uv": [60, 52]},
{"origin": [-1.5, 24.77134, -8.27795], "size": [3, 1, 5], "pivot": [0.03, 25.76134, -6.27795], "rotation": [30, 0, 0], "uv": [46, 26]}
{"origin": [-1.5, 23.88496, -8.81691], "size": [3, 1, 4], "inflate": 0.01, "uv": [65, 28]},
{"origin": [-1.5, 24.90496, -6.81691], "size": [3, 1, 3], "inflate": 0.01, "uv": [60, 52]},
{"origin": [-1.5, 24.8963, -9.08986], "size": [3, 1, 5], "pivot": [0.03, 25.8863, -7.08986], "rotation": [30, 0, 0], "uv": [46, 26]}
]
},
{
@@ -334,6 +334,14 @@
{"origin": [-2, 23.5, -4.65], "size": [4, 2, 0], "inflate": 0.01, "uv": [67, 61]}
]
},
{
"name": "mouth_o",
"parent": "head_angle",
"pivot": [0, 24, 1.35],
"cubes": [
{"origin": [-0.5, 23.5, -4.65], "size": [1, 2, 0], "inflate": 0.01, "uv": [76, 53]}
]
},
{
"name": "neck_fluff",
"parent": "upper_torso",
@@ -334,6 +334,14 @@
{"origin": [-2, 23.5, -4.65], "size": [4, 2, 0], "inflate": 0.01, "uv": [67, 61]}
]
},
{
"name": "mouth_o",
"parent": "head_angle",
"pivot": [0, 24, 1.35],
"cubes": [
{"origin": [-0.5, 23.5, -4.65], "size": [1, 2, 0], "inflate": 0.01, "uv": [76, 53]}
]
},
{
"name": "neck_fluff",
"parent": "upper_torso",
@@ -18,41 +18,20 @@
{
"name": "body",
"parent": "staryu",
"pivot": [0, 8.75, -0.25],
"pivot": [0, 8.35, -0.25]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 8.35, -0.25],
"cubes": [
{"origin": [-3, 5.3, -2.1], "size": [6, 6, 5], "inflate": -0.05, "uv": [0, 0]},
{"origin": [-0.5, 9.27, 1.87], "size": [1, 2, 1], "inflate": -0.01, "uv": [1, 2]}
]
},
{
"name": "face",
"parent": "body",
"pivot": [0, 8.25, -0.9],
"cubes": [
{"origin": [-3.5, 4.75, -3.1], "size": [7, 7, 1], "inflate": 0.11, "uv": [0, 20]},
{"origin": [-4, 4.25, -3.25], "size": [8, 8, 1], "inflate": 0.25, "uv": [0, 11]},
{"origin": [-1.5, 6.75, -4.15], "size": [3, 3, 1], "inflate": 0.1, "uv": [17, 0]}
]
},
{
"name": "locator_eye",
"parent": "face",
"pivot": [0, 8.2, -4.25],
"locators": {
"eye1": [0, 8.2, -4.25]
}
},
{
"name": "gem_emissive",
"parent": "face",
"pivot": [0, 8.25, -3.65],
"cubes": [
{"origin": [-1.5, 6.75, -4.15], "size": [3, 3, 1], "inflate": 0.11, "uv": [36, 0]}
]
},
{
"name": "body_limbs",
"parent": "body",
"parent": "torso",
"pivot": [0, 8.5, -0.25]
},
{
@@ -139,6 +118,32 @@
"cubes": [
{"origin": [-1.75, -1.55, -1], "size": [3, 4, 2], "inflate": 0.15, "uv": [52, 21], "mirror": true}
]
},
{
"name": "face",
"parent": "torso",
"pivot": [0, 8.25, -0.9],
"cubes": [
{"origin": [-3.5, 4.75, -3.1], "size": [7, 7, 1], "inflate": 0.11, "uv": [0, 20]},
{"origin": [-4, 4.25, -3.25], "size": [8, 8, 1], "inflate": 0.25, "uv": [0, 11]},
{"origin": [-1.5, 6.75, -4.15], "size": [3, 3, 1], "inflate": 0.1, "uv": [17, 0]}
]
},
{
"name": "locator_eye",
"parent": "face",
"pivot": [0, 8.2, -4.25],
"locators": {
"eye1": [0, 8.2, -4.25]
}
},
{
"name": "gem_emissive",
"parent": "face",
"pivot": [0, 8.25, -3.65],
"cubes": [
{"origin": [-1.5, 6.75, -4.15], "size": [3, 3, 1], "inflate": 0.11, "uv": [36, 0]}
]
}
]
}
@@ -42,7 +42,8 @@
"parent": "face",
"pivot": [0, 12.5, -8.4],
"locators": {
"eye1": [0, 12.5, -8.4]
"eye1": [0, 12.5, -8.4],
"special": [0, 12.5, -8.4]
}
},
{
@@ -6,7 +6,7 @@
"identifier": "geometry.noctowl",
"texture_width": 128,
"texture_height": 128,
"visible_bounds_width": 6,
"visible_bounds_width": 7,
"visible_bounds_height": 3.5,
"visible_bounds_offset": [0, 1.25, 0]
},
@@ -361,13 +361,21 @@
"parent": "wing_open_left2",
"pivot": [19, 23.5, 0],
"cubes": [
{"origin": [19, 10.5, 0], "size": [14, 14, 0], "inflate": 0.02, "uv": [0, 63]},
{"origin": [19, 11.5, 0], "size": [7, 13, 0], "inflate": 0.02, "uv": [16, 101]},
{"origin": [17, 10.5, 0], "size": [2, 14, 0], "inflate": 0.02, "uv": [56, 92]},
{"origin": [19, 17.5, -0.5], "size": [6, 7, 1], "inflate": 0.02, "uv": [84, 25]},
{"origin": [19, 17.5, -0.5], "size": [6, 0, 1], "inflate": 0.02, "pivot": [22, 17.5, 0], "rotation": [0.5, 0, 0], "uv": [60, 23]},
{"origin": [25, 17.5, -0.5], "size": [0, 7, 1], "inflate": 0.02, "pivot": [25, 21, 0], "rotation": [0, -0.5, 0], "uv": [54, 79]}
]
},
{
"name": "wing_open_left4",
"parent": "wing_open_left3",
"pivot": [25, 23.5, 0],
"cubes": [
{"origin": [25, 14.5, 0], "size": [8, 9, 0], "inflate": 0.02, "uv": [18, 115]}
]
},
{
"name": "wing_open_right1",
"parent": "wings_open",
@@ -402,13 +410,21 @@
"parent": "wing_open_right2",
"pivot": [-19, 23.5, 0],
"cubes": [
{"origin": [-33, 10.5, 0], "size": [14, 14, 0], "inflate": 0.02, "uv": [28, 65]},
{"origin": [-26, 11.5, 0], "size": [7, 13, 0], "inflate": 0.02, "uv": [1, 101]},
{"origin": [-19, 10.5, 0], "size": [2, 14, 0], "inflate": 0.02, "uv": [68, 92]},
{"origin": [-25, 17.5, -0.5], "size": [6, 7, 1], "inflate": 0.02, "uv": [88, 73]},
{"origin": [-25, 17.5, -0.5], "size": [6, 0, 1], "inflate": 0.02, "pivot": [-22, 17.5, 0], "rotation": [0.5, 0, 0], "uv": [60, 24]},
{"origin": [-25, 17.5, -0.5], "size": [0, 7, 1], "inflate": 0.02, "pivot": [-25, 21, 0], "rotation": [0, 0.5, 0], "uv": [96, 3]}
]
},
{
"name": "wing_open_right4",
"parent": "wing_open_right3",
"pivot": [-25, 23.5, 0],
"cubes": [
{"origin": [-33, 14.5, 0], "size": [8, 9, 0], "inflate": 0.02, "uv": [1, 115]}
]
},
{
"name": "wings_closed",
"parent": "torso",
@@ -39,11 +39,11 @@
]
},
{
"name": "locator_seat1",
"name": "locator_seat_1",
"parent": "thorax",
"pivot": [0, 11, 0],
"locators": {
"seat1": [0, 11, 1]
"seat_1": [0, 11, 1]
}
},
{
@@ -79,7 +79,7 @@
"parent": "torso",
"pivot": [0, 21, 3.75],
"locators": {
"seat_2": [0, 21, 3.75]
"seat_1": [0, 21, 3.75]
}
},
{
@@ -78,7 +78,7 @@
"parent": "torso",
"pivot": [0, 21, 3.75],
"locators": {
"seat_2": [0, 21, 3.75]
"seat_1": [0, 21, 3.75]
}
},
{
@@ -377,11 +377,11 @@
]
},
{
"name": "locator_seat1",
"name": "locator_seat_1",
"parent": "saddle",
"pivot": [0, 23.525, 0],
"locators": {
"seat1": [0, 23.525, 0]
"seat_1": [0, 23.525, 0]
}
},
{
@@ -30,6 +30,14 @@
"parent": "body_rotation",
"pivot": [0, 8.5, 0]
},
{
"name": "locator_seat_1",
"parent": "waist_rotation",
"pivot": [0, 36, 0],
"locators": {
"seat_1": [0, 35.75, 8.5]
}
},
{
"name": "waist_scale",
"parent": "waist_rotation",
@@ -188,12 +188,10 @@
"parent": "eyes",
"pivot": [-1.51, 13.3, -1],
"cubes": [
{"origin": [-1.51, 12.8, -2], "size": [0, 1, 2], "uv": [60, 14]},
{"origin": [-1.51, 12.8, -0.5], "size": [0, 1, 2], "uv": [56, 14]},
{"origin": [-1.51, 11.3, -2], "size": [0, 1, 2], "uv": [60, 16]},
{"origin": [-1.51, 11.3, -0.5], "size": [0, 1, 2], "uv": [56, 16]},
{"origin": [-1.51, 11.8, -2], "size": [0, 1, 2], "uv": [60, 15]},
{"origin": [-1.51, 11.8, -0.5], "size": [0, 1, 2], "uv": [56, 15]}
{"origin": [-1.52, 12.8, -2], "size": [0, 1, 1], "uv": [62, 15]},
{"origin": [-1.53, 12.8, -1.5], "size": [0, 1, 3], "uv": [56, 13]},
{"origin": [-1.51, 11.3, -2], "size": [0, 2, 3], "uv": [56, 14]},
{"origin": [-1.52, 11.3, 0.5], "size": [0, 2, 1], "uv": [62, 16]}
]
},
{
@@ -201,8 +199,8 @@
"parent": "eye_right",
"pivot": [-1.51, 13.8, -0.25],
"cubes": [
{"origin": [-1.51, 13.8, -0.5], "size": [0, 1, 2], "uv": [56, 13]},
{"origin": [-1.51, 13.8, -2], "size": [0, 1, 2], "uv": [60, 13]}
{"origin": [-1.53, 13.8, -1.5], "size": [0, 1, 3], "uv": [56, 12]},
{"origin": [-1.52, 13.8, -2], "size": [0, 1, 1], "uv": [62, 14]}
]
},
{
@@ -223,7 +221,7 @@
"parent": "pupil_right",
"pivot": [-1.52, 13, -0.25],
"cubes": [
{"origin": [-1.52, 12.5, -0.75], "size": [0, 1, 1], "uv": [1, 0]}
{"origin": [-1.54, 12.5, -0.75], "size": [0, 1, 1], "uv": [1, 0]}
]
},
{
@@ -240,7 +238,7 @@
"parent": "pupil_right",
"pivot": [-1.42, 13, -1.25],
"cubes": [
{"origin": [-1.42, 12.5, -1.75], "size": [0, 1, 1], "uv": [1, 1]}
{"origin": [-1.44, 12.5, -1.75], "size": [0, 1, 1], "uv": [1, 1]}
]
},
{
@@ -248,7 +246,7 @@
"parent": "pupil_right",
"pivot": [-1.42, 13, 0.75],
"cubes": [
{"origin": [-1.42, 12.5, 0.25], "size": [0, 1, 1], "uv": [1, 2]}
{"origin": [-1.44, 12.5, 0.25], "size": [0, 1, 1], "uv": [1, 2]}
]
},
{
@@ -272,12 +270,10 @@
"parent": "eyes",
"pivot": [1.51, 13.3, -1],
"cubes": [
{"origin": [1.51, 12.8, -2], "size": [0, 1, 2], "uv": [52, 14], "mirror": true},
{"origin": [1.51, 12.8, -0.5], "size": [0, 1, 2], "uv": [48, 14], "mirror": true},
{"origin": [1.51, 11.3, -2], "size": [0, 1, 2], "uv": [52, 16], "mirror": true},
{"origin": [1.51, 11.3, -0.5], "size": [0, 1, 2], "uv": [48, 16], "mirror": true},
{"origin": [1.51, 11.8, -2], "size": [0, 1, 2], "uv": [52, 15], "mirror": true},
{"origin": [1.51, 11.8, -0.5], "size": [0, 1, 2], "uv": [48, 15], "mirror": true}
{"origin": [1.52, 12.8, -2], "size": [0, 1, 1], "uv": [54, 15], "mirror": true},
{"origin": [1.53, 12.8, -1.5], "size": [0, 1, 3], "uv": [48, 13], "mirror": true},
{"origin": [1.51, 11.3, -2], "size": [0, 2, 3], "uv": [48, 14], "mirror": true},
{"origin": [1.52, 11.3, 0.5], "size": [0, 2, 1], "uv": [54, 16], "mirror": true}
]
},
{
@@ -285,8 +281,8 @@
"parent": "eye_left",
"pivot": [1.51, 13.8, -0.25],
"cubes": [
{"origin": [1.51, 13.8, -0.5], "size": [0, 1, 2], "uv": [48, 13], "mirror": true},
{"origin": [1.51, 13.8, -2], "size": [0, 1, 2], "uv": [52, 13], "mirror": true}
{"origin": [1.53, 13.8, -1.5], "size": [0, 1, 3], "uv": [48, 12], "mirror": true},
{"origin": [1.52, 13.8, -2], "size": [0, 1, 1], "uv": [54, 14], "mirror": true}
]
},
{
@@ -307,7 +303,7 @@
"parent": "pupil_left",
"pivot": [1.52, 13, -0.25],
"cubes": [
{"origin": [1.52, 12.5, -0.75], "size": [0, 1, 1], "uv": [3, 0], "mirror": true}
{"origin": [1.54, 12.5, -0.75], "size": [0, 1, 1], "uv": [3, 0], "mirror": true}
]
},
{
@@ -324,7 +320,7 @@
"parent": "pupil_left",
"pivot": [1.42, 13, -1.25],
"cubes": [
{"origin": [1.42, 12.5, -1.75], "size": [0, 1, 1], "uv": [3, 1], "mirror": true}
{"origin": [1.44, 12.5, -1.75], "size": [0, 1, 1], "uv": [3, 1], "mirror": true}
]
},
{
@@ -332,7 +328,7 @@
"parent": "pupil_left",
"pivot": [1.42, 13, 0.75],
"cubes": [
{"origin": [1.42, 12.5, 0.25], "size": [0, 1, 1], "uv": [3, 2], "mirror": true}
{"origin": [1.44, 12.5, 0.25], "size": [0, 1, 1], "uv": [3, 2], "mirror": true}
]
},
{
@@ -188,12 +188,10 @@
"parent": "eyes",
"pivot": [-1.51, 13.3, -1],
"cubes": [
{"origin": [-1.51, 12.8, -2], "size": [0, 1, 2], "uv": [60, 12]},
{"origin": [-1.51, 12.8, -0.5], "size": [0, 1, 2], "uv": [56, 12]},
{"origin": [-1.51, 11.3, -2], "size": [0, 1, 2], "uv": [60, 14]},
{"origin": [-1.51, 11.3, -0.5], "size": [0, 1, 2], "uv": [56, 14]},
{"origin": [-1.51, 11.8, -2], "size": [0, 1, 2], "uv": [60, 13]},
{"origin": [-1.51, 11.8, -0.5], "size": [0, 1, 2], "uv": [56, 13]}
{"origin": [-1.52, 12.8, -2], "size": [0, 1, 1], "uv": [62, 13]},
{"origin": [-1.53, 12.8, -1.5], "size": [0, 1, 3], "uv": [56, 11]},
{"origin": [-1.51, 11.3, -2], "size": [0, 2, 3], "uv": [56, 12]},
{"origin": [-1.52, 11.3, 0.5], "size": [0, 2, 1], "uv": [62, 14]}
]
},
{
@@ -201,8 +199,8 @@
"parent": "eye_right",
"pivot": [-1.51, 13.8, -0.25],
"cubes": [
{"origin": [-1.51, 13.8, -0.5], "size": [0, 1, 2], "uv": [56, 11]},
{"origin": [-1.51, 13.8, -2], "size": [0, 1, 2], "uv": [60, 11]}
{"origin": [-1.53, 13.8, -1.5], "size": [0, 1, 3], "uv": [56, 10]},
{"origin": [-1.52, 13.8, -2], "size": [0, 1, 1], "uv": [62, 12]}
]
},
{
@@ -211,7 +209,7 @@
"pivot": [-1.31, 11.6, 1.3],
"cubes": [
{"origin": [-1.81, 10.6, 0.3], "size": [1, 2, 2], "inflate": -0.3, "uv": [58, 17]},
{"origin": [-1.61, 10.4, 1.5], "size": [1, 1, 1], "inflate": -0.1, "uv": [48, 19]}
{"origin": [-1.62, 10.4, 1.5], "size": [1, 1, 1], "inflate": -0.1, "uv": [48, 19]}
]
},
{
@@ -224,7 +222,7 @@
"parent": "pupil_right",
"pivot": [-1.52, 13, -0.25],
"cubes": [
{"origin": [-1.52, 12.5, -0.75], "size": [0, 1, 1], "uv": [1, 0]}
{"origin": [-1.54, 12.5, -0.75], "size": [0, 1, 1], "uv": [1, 0]}
]
},
{
@@ -257,12 +255,10 @@
"parent": "eyes",
"pivot": [1.51, 13.3, -1],
"cubes": [
{"origin": [1.51, 12.8, -2], "size": [0, 1, 2], "uv": [52, 12], "mirror": true},
{"origin": [1.51, 12.8, -0.5], "size": [0, 1, 2], "uv": [48, 12], "mirror": true},
{"origin": [1.51, 11.3, -2], "size": [0, 1, 2], "uv": [52, 14], "mirror": true},
{"origin": [1.51, 11.3, -0.5], "size": [0, 1, 2], "uv": [48, 14], "mirror": true},
{"origin": [1.51, 11.8, -2], "size": [0, 1, 2], "uv": [52, 13], "mirror": true},
{"origin": [1.51, 11.8, -0.5], "size": [0, 1, 2], "uv": [48, 13], "mirror": true}
{"origin": [1.52, 12.8, -2], "size": [0, 1, 1], "uv": [54, 13], "mirror": true},
{"origin": [1.53, 12.8, -1.5], "size": [0, 1, 3], "uv": [48, 11], "mirror": true},
{"origin": [1.51, 11.3, -2], "size": [0, 2, 3], "uv": [48, 12], "mirror": true},
{"origin": [1.52, 11.3, 0.5], "size": [0, 2, 1], "uv": [54, 14], "mirror": true}
]
},
{
@@ -270,8 +266,8 @@
"parent": "eye_left",
"pivot": [1.51, 13.8, -0.25],
"cubes": [
{"origin": [1.51, 13.8, -0.5], "size": [0, 1, 2], "uv": [48, 11], "mirror": true},
{"origin": [1.51, 13.8, -2], "size": [0, 1, 2], "uv": [52, 11], "mirror": true}
{"origin": [1.53, 13.8, -1.5], "size": [0, 1, 3], "uv": [48, 10], "mirror": true},
{"origin": [1.52, 13.8, -2], "size": [0, 1, 1], "uv": [54, 12], "mirror": true}
]
},
{
@@ -280,7 +276,7 @@
"pivot": [1.31, 11.6, 1.3],
"cubes": [
{"origin": [0.81, 10.6, 0.3], "size": [1, 2, 2], "inflate": -0.3, "uv": [52, 17], "mirror": true},
{"origin": [0.61, 10.4, 1.5], "size": [1, 1, 1], "inflate": -0.1, "uv": [48, 17], "mirror": true}
{"origin": [0.62, 10.4, 1.5], "size": [1, 1, 1], "inflate": -0.1, "uv": [48, 17], "mirror": true}
]
},
{
@@ -293,7 +289,7 @@
"parent": "pupil_left",
"pivot": [1.52, 13, -0.25],
"cubes": [
{"origin": [1.52, 12.5, -0.75], "size": [0, 1, 1], "uv": [3, 0], "mirror": true}
{"origin": [1.54, 12.5, -0.75], "size": [0, 1, 1], "uv": [3, 0], "mirror": true}
]
},
{
@@ -274,6 +274,14 @@
"parent": "lower_gear_rotation",
"pivot": [0, 9, -6]
},
{
"name": "locator_seat_1",
"parent": "lower_gear_rotation",
"pivot": [0, 10.5, -4.5],
"locators": {
"seat_1": [0, 10.5, -4.5]
}
},
{
"name": "gear4",
"parent": "lower_gear",
@@ -447,6 +447,14 @@
"cubes": [
{"origin": [0, -24.5, -8], "size": [0, 12, 7], "uv": [98, 109]}
]
},
{
"name": "locator_seat_1",
"parent": "body",
"pivot": [0, 54, -10],
"locators": {
"seat_1": [0, 54, -10]
}
}
]
}
@@ -494,6 +494,14 @@
"tail_tip": [0, 12.25, 19.25]
}
},
{
"name": "locator_seat_1",
"parent": "tail",
"pivot": [0, 16, 12],
"locators": {
"seat_1": [0, 16, 12]
}
},
{
"name": "legs",
"parent": "body",
@@ -1,450 +1,439 @@
{
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.rabsca",
"texture_width": 256,
"texture_height": 128,
"visible_bounds_width": 4,
"visible_bounds_height": 4.5,
"visible_bounds_offset": [0, 1.75, 0]
},
"bones": [
{
"name": "rabsca",
"pivot": [0, 0, 0]
},
{
"name": "body",
"parent": "rabsca",
"pivot": [0, 10, 0]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 8, 0],
"cubes": [
{"origin": [-4, 10, -2.5], "size": [8, 8, 5], "uv": [0, 9]},
{"origin": [-3.5, 10.52, 2.52], "size": [7, 7, 0], "uv": [52, 28]}
]
},
{
"name": "legs",
"parent": "torso",
"pivot": [0, 14, -2.5]
},
{
"name": "leg_left",
"parent": "legs",
"pivot": [3.5, 14, -2.5],
"rotation": [0, 5, 0],
"cubes": [
{"origin": [2, 13.5, -2.5], "size": [6, 2, 0], "uv": [23, 0]}
]
},
{
"name": "leg_left2",
"parent": "leg_left",
"pivot": [8, 15.5, -2.5],
"cubes": [
{"origin": [5, 15.5, -2.5], "size": [4, 5, 0], "inflate": 0.01, "uv": [35, 0]}
]
},
{
"name": "leg_left3",
"parent": "leg_left2",
"pivot": [9, 20.5, -2.5],
"cubes": [
{"origin": [4, 20.5, -2.5], "size": [5, 5, 0], "inflate": 0.02, "uv": [26, 10]}
]
},
{
"name": "leg_right",
"parent": "legs",
"pivot": [-3.5, 14, -2.5],
"rotation": [0, -5, 0],
"cubes": [
{"origin": [-8, 13.5, -2.5], "size": [6, 2, 0], "uv": [23, 2], "mirror": true}
]
},
{
"name": "leg_right2",
"parent": "leg_right",
"pivot": [-8, 15.5, -2.5],
"cubes": [
{"origin": [-9, 15.5, -2.5], "size": [4, 5, 0], "inflate": 0.01, "uv": [28, 5], "mirror": true}
]
},
{
"name": "leg_right3",
"parent": "leg_right2",
"pivot": [-9, 20.5, -2.5],
"cubes": [
{"origin": [-9, 20.5, -2.5], "size": [5, 5, 0], "inflate": 0.02, "uv": [36, 5], "mirror": true}
]
},
{
"name": "head",
"parent": "torso",
"pivot": [0, 10.5, 0],
"cubes": [
{"origin": [-4.5, 6.5, -2.5], "size": [9, 4, 5], "inflate": 0.01, "uv": [0, 0]},
{"origin": [1.25, 4.75, -0.25], "size": [0, 4, 3], "pivot": [1.25, 8.25, 2.6], "rotation": [15, 0, -5], "uv": [0, 19]},
{"origin": [2.5, 5, -0.25], "size": [0, 4, 3], "pivot": [2.5, 8.25, 2.6], "rotation": [15, 0, -20], "uv": [0, 23]},
{"origin": [-1.25, 4.75, -0.25], "size": [0, 4, 3], "pivot": [-1.25, 8.25, 2.6], "rotation": [15, 0, 5], "uv": [6, 19], "mirror": true},
{"origin": [-2.5, 5, -0.25], "size": [0, 4, 3], "pivot": [-2.5, 8.25, 2.6], "rotation": [15, 0, 20], "uv": [6, 23], "mirror": true},
{"origin": [-0.5, 6.71716, -2.67], "size": [1, 1, 1], "inflate": -0.15, "pivot": [0, 7.21716, -2.17], "rotation": [0, 0, 45], "uv": [21, 9]}
]
},
{
"name": "nose",
"parent": "head",
"pivot": [0, 10.5, -2.5],
"rotation": [12.5, 0, 0],
"cubes": [
{"origin": [-1, 9.5, -2.51], "size": [2, 2, 1], "pivot": [0, 10.5, -2], "rotation": [0, 0, -45], "uv": [57, 0]}
]
},
{
"name": "beard",
"parent": "head",
"pivot": [0, 10.5, -2.5],
"rotation": [5, 0, 0]
},
{
"name": "beard_middle",
"parent": "beard",
"pivot": [0, 10.5, -2.5],
"rotation": [2.5, 0, 0],
"cubes": [
{"origin": [-3, 10.25, -2.5], "size": [6, 2, 0], "uv": [26, 15]}
]
},
{
"name": "beard_left",
"parent": "beard",
"pivot": [2.5, 10.5, -2.5],
"rotation": [0, 0, 42.5]
},
{
"name": "beard_left_rotation",
"parent": "beard_left",
"pivot": [2.5, 10.5, -2.5],
"rotation": [5, 0, 0],
"cubes": [
{"origin": [2.5, 10, -2.5], "size": [2, 4, 0], "uv": [26, 17]}
]
},
{
"name": "beard_left2",
"parent": "beard_left_rotation",
"pivot": [2.5, 14, -2.5],
"cubes": [
{"origin": [2.5, 14, -2.5], "size": [4, 3, 0], "inflate": 0.01, "uv": [38, 15]}
]
},
{
"name": "beard_left3",
"parent": "beard_left2",
"pivot": [6.5, 16, -2.5],
"rotation": [0, 0, 5],
"cubes": [
{"origin": [6.5, 14, -2.5], "size": [6, 4, 0], "inflate": 0.02, "uv": [46, 17]}
]
},
{
"name": "beard_left4",
"parent": "beard_left3",
"pivot": [12.5, 18, -2.5],
"rotation": [0, 0, 5],
"cubes": [
{"origin": [12.5, 13, -2.5], "size": [8, 5, 0], "inflate": 0.01, "uv": [36, 21]}
]
},
{
"name": "beard_right",
"parent": "beard",
"pivot": [-2.5, 10.5, -2.5],
"rotation": [0, 0, -42.5]
},
{
"name": "beard_right_rotation",
"parent": "beard_right",
"pivot": [-2.5, 10.5, -2.5],
"rotation": [5, 0, 0],
"cubes": [
{"origin": [-4.5, 10, -2.5], "size": [2, 4, 0], "uv": [30, 17], "mirror": true}
]
},
{
"name": "beard_right2",
"parent": "beard_right_rotation",
"pivot": [-2.5, 14, -2.5],
"cubes": [
{"origin": [-6.5, 14, -2.5], "size": [4, 3, 0], "inflate": 0.01, "uv": [34, 18], "mirror": true}
]
},
{
"name": "beard_right3",
"parent": "beard_right2",
"pivot": [-6.5, 16, -2.5],
"rotation": [0, 0, -5],
"cubes": [
{"origin": [-12.5, 14, -2.5], "size": [6, 4, 0], "inflate": 0.02, "uv": [52, 21], "mirror": true}
]
},
{
"name": "beard_right4",
"parent": "beard_right3",
"pivot": [-12.5, 18, -2.5],
"rotation": [0, 0, -5],
"cubes": [
{"origin": [-20.5, 13, -2.5], "size": [8, 5, 0], "inflate": 0.01, "uv": [36, 26], "mirror": true}
]
},
{
"name": "eyebrow_left",
"parent": "head",
"pivot": [1.5, 6.5, -2.52],
"rotation": [-2.5, 0, -15],
"cubes": [
{"origin": [1.5, 1, -2.52], "size": [3, 7, 0], "uv": [57, 3]}
]
},
{
"name": "eyebrow_right",
"parent": "head",
"pivot": [-1.5, 6.5, -2.52],
"rotation": [-2.5, 0, 15],
"cubes": [
{"origin": [-4.5, 1, -2.52], "size": [3, 7, 0], "uv": [56, 10], "mirror": true}
]
},
{
"name": "eyes",
"parent": "head",
"pivot": [0, 9, -2.52]
},
{
"name": "eye_left",
"parent": "eyes",
"pivot": [2, 9.5, -2.52],
"rotation": [0, 0, 10]
},
{
"name": "eye_open_left",
"parent": "eye_left",
"pivot": [-2, 9.5, -2.42],
"cubes": [
{"origin": [1, 8.8, -2.41], "size": [2, 1.4, 0], "inflate": 0.01, "uv": [0, 9]}
]
},
{
"name": "pupil_left",
"parent": "eye_open_left",
"pivot": [-2, 9.5, -2.43],
"cubes": [
{"origin": [1.5, 9, -2.43], "size": [1, 1, 0], "pivot": [2, 9.5, -2.43], "rotation": [0, 0, 45], "uv": [0, 11]}
]
},
{
"name": "eye_closed_left",
"parent": "eye_left",
"pivot": [-2, 9.5, -2.52],
"cubes": [
{"origin": [1, 9, -2.52], "size": [2, 1, 0], "uv": [0, 0]}
]
},
{
"name": "locator_eye_left",
"parent": "eye_left",
"pivot": [2, 9.5, -2.5],
"locators": {
"eye2": [2, 9.5, -2.5]
}
},
{
"name": "eye_right",
"parent": "eyes",
"pivot": [-2, 9.5, -2.52],
"rotation": [0, 0, -10]
},
{
"name": "eye_open_right",
"parent": "eye_right",
"pivot": [-2, 9.5, -2.42],
"cubes": [
{"origin": [-3, 8.8, -2.41], "size": [2, 1.4, 0], "inflate": 0.01, "uv": [0, 10], "mirror": true}
]
},
{
"name": "pupil_right",
"parent": "eye_open_right",
"pivot": [-2, 9.5, -2.43],
"cubes": [
{"origin": [-2.5, 9, -2.43], "size": [1, 1, 0], "pivot": [-2, 9.5, -2.43], "rotation": [0, 0, -45], "uv": [0, 12], "mirror": true}
]
},
{
"name": "eye_closed_right",
"parent": "eye_right",
"pivot": [-2, 9.5, -2.52],
"cubes": [
{"origin": [-3, 9, -2.52], "size": [2, 1, 0], "uv": [0, 1], "mirror": true}
]
},
{
"name": "locator_eye_right",
"parent": "eye_right",
"pivot": [-2, 9.5, -2.5],
"locators": {
"eye1": [-2, 9.5, -2.5]
}
},
{
"name": "arms",
"parent": "body",
"pivot": [0, 9.75, -2.5]
},
{
"name": "arm_left",
"parent": "arms",
"pivot": [4, 9.75, -2.5],
"rotation": [0, 5, 0],
"cubes": [
{"origin": [2.5, 8.25, -2.5], "size": [7, 2, 0], "uv": [43, 0]}
]
},
{
"name": "arm_left2",
"parent": "arm_left",
"pivot": [9.5, 8.25, -2.5],
"cubes": [
{"origin": [6.5, 3.25, -2.5], "size": [5, 5, 0], "inflate": 0.01, "uv": [46, 4]}
]
},
{
"name": "arm_left3",
"parent": "arm_left2",
"pivot": [8.5, 3.25, -2.5],
"cubes": [
{"origin": [6.5, 0.25, -2.5], "size": [5, 3, 0], "inflate": 0.02, "uv": [46, 9]}
]
},
{
"name": "arm_right",
"parent": "arms",
"pivot": [-4, 9.75, -2.5],
"rotation": [0, -5, 0],
"cubes": [
{"origin": [-9.5, 8.25, -2.5], "size": [7, 2, 0], "uv": [43, 2], "mirror": true}
]
},
{
"name": "arm_right2",
"parent": "arm_right",
"pivot": [-9.5, 8.25, -2.5],
"cubes": [
{"origin": [-11.5, 3.25, -2.5], "size": [5, 5, 0], "inflate": 0.01, "uv": [36, 10], "mirror": true}
]
},
{
"name": "arm_right3",
"parent": "arm_right2",
"pivot": [-8.5, 3.25, -2.5],
"cubes": [
{"origin": [-11.5, 0.25, -2.5], "size": [5, 3, 0], "inflate": 0.02, "uv": [46, 12], "mirror": true}
]
},
{
"name": "ball",
"parent": "rabsca",
"pivot": [0, 39, 0]
},
{
"name": "ball_rotation",
"parent": "ball",
"pivot": [0, 39, 0]
},
{
"name": "ball_inactive",
"parent": "ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-10, 29, -10], "size": [20, 20, 0], "inflate": 0.01, "uv": [0, 88]},
{"origin": [-10, 29, 10], "size": [20, 20, 0], "inflate": 0.01, "uv": [0, 108]},
{"origin": [-10, 49, -10], "size": [20, 0, 20], "inflate": 0.01, "uv": [-20, 48]},
{"origin": [-10, 29, -10], "size": [20, 0, 20], "inflate": 0.01, "uv": [-20, 68]},
{"origin": [10, 29, -10], "size": [0, 20, 20], "inflate": 0.01, "uv": [40, 29]},
{"origin": [-10, 29, -10], "size": [0, 20, 20], "inflate": 0.01, "uv": [40, 49], "mirror": true}
]
},
{
"name": "ball_active",
"parent": "ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-10, 29, -10], "size": [20, 20, 0], "inflate": 0.01, "uv": [108, 40]},
{"origin": [-10, 29, 10], "size": [20, 20, 0], "inflate": 0.01, "uv": [108, 60]},
{"origin": [-10, 49, -10], "size": [20, 0, 20], "inflate": 0.01, "uv": [96, 0]},
{"origin": [-10, 29, -10], "size": [20, 0, 20], "inflate": 0.01, "uv": [96, 20]},
{"origin": [10, 29, -10], "size": [0, 20, 20], "inflate": 0.01, "uv": [108, 60]},
{"origin": [-10, 29, -10], "size": [0, 20, 20], "inflate": 0.01, "uv": [118, 80], "mirror": true}
]
},
{
"name": "inner_ball_rotation",
"parent": "ball_rotation",
"pivot": [0, 39, 0]
},
{
"name": "inner_ball",
"parent": "inner_ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-6, 33, -6], "size": [12, 12, 12], "uv": [0, 24]}
]
},
{
"name": "inner_ball_active",
"parent": "inner_ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-6, 33, -6], "size": [12, 12, 12], "uv": [156, 0]}
]
},
{
"name": "grub",
"parent": "inner_ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-3.5, 38, -3.5], "size": [7, 3, 7], "uv": [48, 35]},
{"origin": [-2.5, 36, -2.5], "size": [5, 2, 5], "uv": [66, 28]},
{"origin": [-1.5, 34, -1.5], "size": [3, 2, 3], "uv": [40, 31]},
{"origin": [-2.5, 40.75, -2.5], "size": [5, 2, 5], "inflate": 0.1, "uv": [81, 30]},
{"origin": [-0.5, 42.25, -0.5], "size": [1, 2, 1], "uv": [82, 30]},
{"origin": [0.4, 41.2, -2.61], "size": [2, 1, 0], "pivot": [1.5, 41.75, -2.61], "rotation": [0, 0, 30], "uv": [81, 28]},
{"origin": [-2.4, 41.2, -2.61], "size": [2, 1, 0], "pivot": [-1.5, 41.75, -2.61], "rotation": [0, 0, -30], "uv": [81, 29], "mirror": true}
]
},
{
"name": "ball_cloud",
"parent": "ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-13, 26, -6.5], "size": [26, 26, 13], "uv": [40, 89]},
{"origin": [-13, 52, -7], "size": [26, 0, 7], "pivot": [0, 52, 0], "rotation": [-12.5, 0, 0], "uv": [57, 0]},
{"origin": [-13, 52, 0], "size": [26, 0, 7], "pivot": [0, 52, 0], "rotation": [12.5, 0, 0], "uv": [57, 7]},
{"origin": [-13, 26, -7], "size": [26, 0, 7], "pivot": [0, 26, 0], "rotation": [12.5, 0, 0], "uv": [57, 14]},
{"origin": [-13, 26, 0], "size": [26, 0, 7], "pivot": [0, 26, 0], "rotation": [-12.5, 0, 0], "uv": [57, 21]},
{"origin": [13, 26, -7], "size": [0, 26, 7], "pivot": [13, 39, 0], "rotation": [0, -12.5, 0], "uv": [80, 30]},
{"origin": [13, 26, 0], "size": [0, 26, 7], "pivot": [13, 39, 0], "rotation": [0, 12.5, 0], "uv": [94, 30]},
{"origin": [-13, 26, -7], "size": [0, 26, 7], "pivot": [-13, 39, 0], "rotation": [0, 12.5, 0], "uv": [80, 56], "mirror": true},
{"origin": [-13, 26, 0], "size": [0, 26, 7], "pivot": [-13, 39, 0], "rotation": [0, -12.5, 0], "uv": [94, 56], "mirror": true}
]
}
]
}
]
"format_version": "1.12.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.rabsca",
"texture_width": 256,
"texture_height": 128,
"visible_bounds_width": 4,
"visible_bounds_height": 5.5,
"visible_bounds_offset": [0, 2.25, 0]
},
"bones": [
{
"name": "rabsca",
"pivot": [0, 0, 0]
},
{
"name": "body2",
"parent": "rabsca",
"pivot": [0, 26, 0]
},
{
"name": "body",
"parent": "body2",
"pivot": [0, 10, 0]
},
{
"name": "torso",
"parent": "body",
"pivot": [0, 8, 0],
"cubes": [
{"origin": [-4, 10, -2.5], "size": [8, 8, 5], "uv": [0, 9]},
{"origin": [-3.5, 10.52, 2.52], "size": [7, 7, 0], "uv": [52, 28]}
]
},
{
"name": "legs",
"parent": "torso",
"pivot": [0, 14, -2.5]
},
{
"name": "leg_left",
"parent": "legs",
"pivot": [3.5, 14, -2.5],
"rotation": [0, 5, 0],
"cubes": [
{"origin": [2, 13.5, -2.5], "size": [6, 2, 0], "uv": [23, 0]}
]
},
{
"name": "leg_left2",
"parent": "leg_left",
"pivot": [8, 15.5, -2.5],
"cubes": [
{"origin": [5, 15.5, -2.5], "size": [4, 5, 0], "inflate": 0.01, "uv": [35, 0]}
]
},
{
"name": "leg_left3",
"parent": "leg_left2",
"pivot": [9, 20.5, -2.5],
"cubes": [
{"origin": [4, 20.5, -2.5], "size": [5, 5, 0], "inflate": 0.02, "uv": [26, 10]}
]
},
{
"name": "leg_right",
"parent": "legs",
"pivot": [-3.5, 14, -2.5],
"rotation": [0, -5, 0],
"cubes": [
{"origin": [-8, 13.5, -2.5], "size": [6, 2, 0], "uv": [23, 2], "mirror": true}
]
},
{
"name": "leg_right2",
"parent": "leg_right",
"pivot": [-8, 15.5, -2.5],
"cubes": [
{"origin": [-9, 15.5, -2.5], "size": [4, 5, 0], "inflate": 0.01, "uv": [28, 5], "mirror": true}
]
},
{
"name": "leg_right3",
"parent": "leg_right2",
"pivot": [-9, 20.5, -2.5],
"cubes": [
{"origin": [-9, 20.5, -2.5], "size": [5, 5, 0], "inflate": 0.02, "uv": [36, 5], "mirror": true}
]
},
{
"name": "head",
"parent": "torso",
"pivot": [0, 10.5, 0],
"cubes": [
{"origin": [-4.5, 6.5, -2.5], "size": [9, 4, 5], "inflate": 0.01, "uv": [0, 0]},
{"origin": [1.25, 4.75, -0.25], "size": [0, 4, 3], "pivot": [1.25, 8.25, 2.6], "rotation": [15, 0, -5], "uv": [0, 19]},
{"origin": [2.5, 5, -0.25], "size": [0, 4, 3], "pivot": [2.5, 8.25, 2.6], "rotation": [15, 0, -20], "uv": [0, 23]},
{"origin": [-1.25, 4.75, -0.25], "size": [0, 4, 3], "pivot": [-1.25, 8.25, 2.6], "rotation": [15, 0, 5], "uv": [6, 19], "mirror": true},
{"origin": [-2.5, 5, -0.25], "size": [0, 4, 3], "pivot": [-2.5, 8.25, 2.6], "rotation": [15, 0, 20], "uv": [6, 23], "mirror": true},
{"origin": [-0.5, 6.71716, -2.67], "size": [1, 1, 1], "inflate": -0.15, "pivot": [0, 7.21716, -2.17], "rotation": [0, 0, 45], "uv": [21, 9]}
]
},
{
"name": "nose",
"parent": "head",
"pivot": [0, 10.5, -2.5],
"rotation": [12.5, 0, 0],
"cubes": [
{"origin": [-1, 9.5, -2.51], "size": [2, 2, 1], "pivot": [0, 10.5, -2], "rotation": [0, 0, -45], "uv": [57, 0]}
]
},
{
"name": "beard",
"parent": "head",
"pivot": [0, 10.5, -2.5],
"rotation": [5, 0, 0]
},
{
"name": "beard_middle",
"parent": "beard",
"pivot": [0, 10.5, -2.5],
"rotation": [2.5, 0, 0],
"cubes": [
{"origin": [-3, 10.25, -2.5], "size": [6, 2, 0], "uv": [26, 15]}
]
},
{
"name": "beard_left",
"parent": "beard",
"pivot": [2.5, 10.5, -2.5],
"rotation": [0, 0, 42.5]
},
{
"name": "beard_left_rotation",
"parent": "beard_left",
"pivot": [2.5, 10.5, -2.5],
"rotation": [5, 0, 0],
"cubes": [
{"origin": [2.5, 10, -2.5], "size": [2, 4, 0], "uv": [26, 17]}
]
},
{
"name": "beard_left2",
"parent": "beard_left_rotation",
"pivot": [2.5, 14, -2.5],
"cubes": [
{"origin": [2.5, 14, -2.5], "size": [4, 3, 0], "inflate": 0.01, "uv": [38, 15]}
]
},
{
"name": "beard_left3",
"parent": "beard_left2",
"pivot": [6.5, 16, -2.5],
"rotation": [0, 0, 5],
"cubes": [
{"origin": [6.5, 14, -2.5], "size": [6, 4, 0], "inflate": 0.02, "uv": [46, 17]}
]
},
{
"name": "beard_left4",
"parent": "beard_left3",
"pivot": [12.5, 18, -2.5],
"rotation": [0, 0, 5],
"cubes": [
{"origin": [12.5, 13, -2.5], "size": [8, 5, 0], "inflate": 0.01, "uv": [36, 21]}
]
},
{
"name": "beard_right",
"parent": "beard",
"pivot": [-2.5, 10.5, -2.5],
"rotation": [0, 0, -42.5]
},
{
"name": "beard_right_rotation",
"parent": "beard_right",
"pivot": [-2.5, 10.5, -2.5],
"rotation": [5, 0, 0],
"cubes": [
{"origin": [-4.5, 10, -2.5], "size": [2, 4, 0], "uv": [30, 17], "mirror": true}
]
},
{
"name": "beard_right2",
"parent": "beard_right_rotation",
"pivot": [-2.5, 14, -2.5],
"cubes": [
{"origin": [-6.5, 14, -2.5], "size": [4, 3, 0], "inflate": 0.01, "uv": [34, 18], "mirror": true}
]
},
{
"name": "beard_right3",
"parent": "beard_right2",
"pivot": [-6.5, 16, -2.5],
"rotation": [0, 0, -5],
"cubes": [
{"origin": [-12.5, 14, -2.5], "size": [6, 4, 0], "inflate": 0.02, "uv": [52, 21], "mirror": true}
]
},
{
"name": "beard_right4",
"parent": "beard_right3",
"pivot": [-12.5, 18, -2.5],
"rotation": [0, 0, -5],
"cubes": [
{"origin": [-20.5, 13, -2.5], "size": [8, 5, 0], "inflate": 0.01, "uv": [36, 26], "mirror": true}
]
},
{
"name": "eyebrow_left",
"parent": "head",
"pivot": [1.5, 6.5, -2.52],
"rotation": [-2.5, 0, -15],
"cubes": [
{"origin": [1.5, 1, -2.52], "size": [3, 7, 0], "uv": [57, 3]}
]
},
{
"name": "eyebrow_right",
"parent": "head",
"pivot": [-1.5, 6.5, -2.52],
"rotation": [-2.5, 0, 15],
"cubes": [
{"origin": [-4.5, 1, -2.52], "size": [3, 7, 0], "uv": [56, 10], "mirror": true}
]
},
{
"name": "eyes",
"parent": "head",
"pivot": [0, 9, -2.52]
},
{
"name": "eye_left",
"parent": "eyes",
"pivot": [2, 9.5, -2.52],
"rotation": [0, 0, 10]
},
{
"name": "eye_open_left",
"parent": "eye_left",
"pivot": [2, 9.5, -2.42],
"cubes": [
{"origin": [1, 8.8, -2.41], "size": [2, 1.4, 0], "inflate": 0.01, "uv": [0, 9]}
]
},
{
"name": "pupil_left",
"parent": "eye_open_left",
"pivot": [2, 9.5, -2.43],
"cubes": [
{"origin": [1.5, 9, -2.43], "size": [1, 1, 0], "pivot": [2, 9.5, -2.43], "rotation": [0, 0, 45], "uv": [0, 11]}
]
},
{
"name": "eye_closed_left",
"parent": "eye_left",
"pivot": [2, 9.5, -2.52],
"cubes": [
{"origin": [1, 9, -2.52], "size": [2, 1, 0], "uv": [0, 0]}
]
},
{
"name": "eye_right",
"parent": "eyes",
"pivot": [-2, 9.5, -2.52],
"rotation": [0, 0, -10]
},
{
"name": "eye_open_right",
"parent": "eye_right",
"pivot": [-2, 9.5, -2.42],
"cubes": [
{"origin": [-3, 8.8, -2.41], "size": [2, 1.4, 0], "inflate": 0.01, "uv": [0, 10], "mirror": true}
]
},
{
"name": "pupil_right",
"parent": "eye_open_right",
"pivot": [-2, 9.5, -2.43],
"cubes": [
{"origin": [-2.5, 9, -2.43], "size": [1, 1, 0], "pivot": [-2, 9.5, -2.43], "rotation": [0, 0, -45], "uv": [0, 12], "mirror": true}
]
},
{
"name": "eye_closed_right",
"parent": "eye_right",
"pivot": [-2, 9.5, -2.52],
"cubes": [
{"origin": [-3, 9, -2.52], "size": [2, 1, 0], "uv": [0, 1], "mirror": true}
]
},
{
"name": "arms",
"parent": "body",
"pivot": [0, 9.75, -2.5]
},
{
"name": "arm_left",
"parent": "arms",
"pivot": [4, 9.75, -2.5],
"rotation": [0, 5, 0],
"cubes": [
{"origin": [2.5, 8.25, -2.5], "size": [7, 2, 0], "uv": [43, 0]}
]
},
{
"name": "arm_left2",
"parent": "arm_left",
"pivot": [9.5, 8.25, -2.5],
"cubes": [
{"origin": [6.5, 3.25, -2.5], "size": [5, 5, 0], "inflate": 0.01, "uv": [46, 4]}
]
},
{
"name": "arm_left3",
"parent": "arm_left2",
"pivot": [8.5, 3.25, -2.5],
"cubes": [
{"origin": [6.5, 0.25, -2.5], "size": [5, 3, 0], "inflate": 0.02, "uv": [46, 9]}
]
},
{
"name": "arm_right",
"parent": "arms",
"pivot": [-4, 9.75, -2.5],
"rotation": [0, -5, 0],
"cubes": [
{"origin": [-9.5, 8.25, -2.5], "size": [7, 2, 0], "uv": [43, 2], "mirror": true}
]
},
{
"name": "arm_right2",
"parent": "arm_right",
"pivot": [-9.5, 8.25, -2.5],
"cubes": [
{"origin": [-11.5, 3.25, -2.5], "size": [5, 5, 0], "inflate": 0.01, "uv": [36, 10], "mirror": true}
]
},
{
"name": "arm_right3",
"parent": "arm_right2",
"pivot": [-8.5, 3.25, -2.5],
"cubes": [
{"origin": [-11.5, 0.25, -2.5], "size": [5, 3, 0], "inflate": 0.02, "uv": [46, 12], "mirror": true}
]
},
{
"name": "ball",
"parent": "body2",
"pivot": [0, 39, 0]
},
{
"name": "ball_rotation",
"parent": "ball",
"pivot": [0, 39, 0]
},
{
"name": "ball_inactive",
"parent": "ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-10, 29, -10], "size": [20, 20, 0], "inflate": 0.01, "uv": [0, 88]},
{"origin": [-10, 29, 10], "size": [20, 20, 0], "inflate": 0.01, "uv": [0, 108]},
{"origin": [-10, 49, -10], "size": [20, 0, 20], "inflate": 0.01, "uv": [-20, 48]},
{"origin": [-10, 29, -10], "size": [20, 0, 20], "inflate": 0.01, "uv": [-20, 68]},
{"origin": [10, 29, -10], "size": [0, 20, 20], "inflate": 0.01, "uv": [40, 29]},
{"origin": [-10, 29, -10], "size": [0, 20, 20], "inflate": 0.01, "uv": [40, 49], "mirror": true}
]
},
{
"name": "ball_active",
"parent": "ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-10, 29, -10], "size": [20, 20, 0], "inflate": 0.01, "uv": [108, 40]},
{"origin": [-10, 29, 10], "size": [20, 20, 0], "inflate": 0.01, "uv": [108, 60]},
{"origin": [-10, 49, -10], "size": [20, 0, 20], "inflate": 0.01, "uv": [96, 0]},
{"origin": [-10, 29, -10], "size": [20, 0, 20], "inflate": 0.01, "uv": [96, 20]},
{"origin": [10, 29, -10], "size": [0, 20, 20], "inflate": 0.01, "uv": [108, 60]},
{"origin": [-10, 29, -10], "size": [0, 20, 20], "inflate": 0.01, "uv": [118, 80], "mirror": true}
]
},
{
"name": "inner_ball_rotation",
"parent": "ball_rotation",
"pivot": [0, 39, 0]
},
{
"name": "inner_ball",
"parent": "inner_ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-6, 33, -6], "size": [12, 12, 12], "uv": [0, 24]}
]
},
{
"name": "inner_ball_active",
"parent": "inner_ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-6, 33, -6], "size": [12, 12, 12], "uv": [156, 0]}
]
},
{
"name": "grub",
"parent": "inner_ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-3.5, 38, -3.5], "size": [7, 3, 7], "uv": [48, 35]},
{"origin": [-2.5, 36, -2.5], "size": [5, 2, 5], "uv": [66, 28]},
{"origin": [-1.5, 34, -1.5], "size": [3, 2, 3], "uv": [40, 31]},
{"origin": [-2.5, 40.75, -2.5], "size": [5, 2, 5], "inflate": 0.1, "uv": [81, 30]},
{"origin": [-0.5, 42.25, -0.5], "size": [1, 2, 1], "uv": [82, 30]},
{"origin": [0.4, 41.2, -2.61], "size": [2, 1, 0], "pivot": [1.5, 41.75, -2.61], "rotation": [0, 0, 30], "uv": [81, 28]},
{"origin": [-2.4, 41.2, -2.61], "size": [2, 1, 0], "pivot": [-1.5, 41.75, -2.61], "rotation": [0, 0, -30], "uv": [81, 29], "mirror": true}
]
},
{
"name": "ball_cloud",
"parent": "ball_rotation",
"pivot": [0, 39, 0],
"cubes": [
{"origin": [-13, 26, -6.5], "size": [26, 26, 13], "uv": [40, 89]},
{"origin": [-13, 52, -7], "size": [26, 0, 7], "pivot": [0, 52, 0], "rotation": [-12.5, 0, 0], "uv": [57, 0]},
{"origin": [-13, 52, 0], "size": [26, 0, 7], "pivot": [0, 52, 0], "rotation": [12.5, 0, 0], "uv": [57, 7]},
{"origin": [-13, 26, -7], "size": [26, 0, 7], "pivot": [0, 26, 0], "rotation": [12.5, 0, 0], "uv": [57, 14]},
{"origin": [-13, 26, 0], "size": [26, 0, 7], "pivot": [0, 26, 0], "rotation": [-12.5, 0, 0], "uv": [57, 21]},
{"origin": [13, 26, -7], "size": [0, 26, 7], "pivot": [13, 39, 0], "rotation": [0, -12.5, 0], "uv": [80, 30]},
{"origin": [13, 26, 0], "size": [0, 26, 7], "pivot": [13, 39, 0], "rotation": [0, 12.5, 0], "uv": [94, 30]},
{"origin": [-13, 26, -7], "size": [0, 26, 7], "pivot": [-13, 39, 0], "rotation": [0, 12.5, 0], "uv": [80, 56], "mirror": true},
{"origin": [-13, 26, 0], "size": [0, 26, 7], "pivot": [-13, 39, 0], "rotation": [0, -12.5, 0], "uv": [94, 56], "mirror": true}
]
}
]
}
]
}
@@ -474,6 +474,67 @@
"cubes": [
{"origin": [27, 10.5, 5], "size": [15, 19, 0], "uv": [223, 39]}
]
},
{
"name": "locator_seat_1",
"parent": "torso",
"pivot": [0, 30, -19],
"locators": {
"seat_1": [0, 30, -19]
}
},
{
"name": "locator_seat_2",
"parent": "torso",
"pivot": [13, 30, -14],
"rotation": [0, -90, 0],
"locators": {
"seat_2": [13, 30, -14]
}
},
{
"name": "locator_seat_3",
"parent": "torso",
"pivot": [-13, 30, -14],
"rotation": [0, 90, 0],
"locators": {
"seat_3": [-13, 30, -14]
}
},
{
"name": "locator_seat_4",
"parent": "torso",
"pivot": [0, 34, -3],
"locators": {
"seat_4": [0, 34, -3]
}
},
{
"name": "locator_seat_5",
"parent": "torso",
"pivot": [13, 30, 2],
"rotation": [0, -90, 0],
"locators": {
"seat_5": [13, 30, 2]
}
},
{
"name": "locator_seat_6",
"parent": "torso",
"pivot": [-13, 30, 2],
"rotation": [0, 90, 0],
"locators": {
"seat_6": [-13, 30, 2]
}
},
{
"name": "locator_seat_7",
"parent": "torso",
"pivot": [0, 33, 7],
"rotation": [0, 180, 0],
"locators": {
"seat_7": [0, 33, 7]
}
}
]
}
@@ -620,6 +620,14 @@
{"origin": [-4.98, 15.25, 20.99], "size": [0, 2, 2], "inflate": 0.01, "uv": [93, 70], "mirror": true}
]
},
{
"name": "locator_seat_1",
"parent": "torso_back",
"pivot": [0, 11, 14],
"locators": {
"seat_1": [0, 11, 14]
}
},
{
"name": "legs",
"parent": "body",
@@ -2,7 +2,8 @@
"portraitScale": 1.03,
"portraitTranslation": [-0.31, 0.12, 0],
"profileScale": 0.47,
"profileTranslation": [0, 0.98, 0.0],
"profileTranslation": [0.07, 0.98, 0.0],
"profilePokedexTranslation": [0, 0.98, 0],
"rootBone": "venusaur",
"firstPersonCameraOffset": {
"seat_1": [0, 0.25, 0]
@@ -1,8 +1,8 @@
{
"portraitScale": 1.89,
"portraitTranslation": [-0.13, 0.91, 0],
"profileScale": 0.63,
"profileTranslation": [0, 0.81, 0],
"profileScale": 0.77,
"profileTranslation": [0, 0.65, 0],
"rootBone": "charmeleon",
"animations": {
"cry": "q.bedrock_stateful('charmeleon', 'cry')"
@@ -2,7 +2,7 @@
"portraitScale": 2.1,
"portraitTranslation": [-1.11, 2.43, 0],
"profileScale": 0.54,
"profileTranslation": [0, 0.96, -10],
"profileTranslation": [0, 0.92, -10],
"rootBone": "charizard",
"firstPersonCameraOffset": {
"seat_1": [0, 0.45, 0]
@@ -1,8 +1,8 @@
{
"portraitScale": 1.89,
"portraitTranslation": [-0.8, 1.36, 0.0],
"profileScale": 0.59,
"profileTranslation": [0, 0.84, 0.0],
"profileScale": 0.57,
"profileTranslation": [0, 0.81, 0.0],
"rootBone": "nidoking",
"animations": {
"cry": "q.bedrock_stateful('nidoking', 'cry')",
Loaded 100 of 199 files, more files were not shown because too many files have changed in this diff. Show more