mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-22 23:26:25 -04:00
Compare commits
85
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a602df2fb8 | ||
|
|
f4d64eb05b | ||
|
|
ce3f703de2 | ||
|
|
8ed68742df | ||
|
|
16aa930735 | ||
|
|
55733e8ad5 | ||
|
|
67591efdad | ||
|
|
5d300c8157 | ||
|
|
c77198a845 | ||
|
|
bd32c07cc1 | ||
|
|
99cfc4f147 | ||
|
|
89281a1f6d | ||
|
|
ad044fb05c | ||
|
|
7088ce3828 | ||
|
|
fc6a712906 | ||
|
|
1d0397c399 | ||
|
|
8ad443a4c5 | ||
|
|
0d1f9a0093 | ||
|
|
7587344cb4 | ||
|
|
f0926d7524 | ||
|
|
7c3b17d841 | ||
|
|
263e3cd79f | ||
|
|
2ba8062915 | ||
|
|
edc298bf64 | ||
|
|
aa1158fcfe | ||
|
|
ab40ae81c4 | ||
|
|
b5df1878ed | ||
|
|
800965cb40 | ||
|
|
b00f1d9352 | ||
|
|
a588cfadf8 | ||
|
|
2eb4062f67 | ||
|
|
43321d8872 | ||
|
|
a5ea584b75 | ||
|
|
6a9edc2e67 | ||
|
|
12377deff7 | ||
|
|
583377d39b | ||
|
|
2c1da8df06 | ||
|
|
737ddd973b | ||
|
|
d749b04261 | ||
|
|
93deb3a669 | ||
|
|
dca45a95e9 | ||
|
|
0412f16460 | ||
|
|
a62e5a6571 | ||
|
|
0ec337ee6c | ||
|
|
76df0a429d | ||
|
|
08ea9378de | ||
|
|
c2bd21ab96 | ||
|
|
5db8ccfad4 | ||
|
|
aa206d386a | ||
|
|
a235af6c01 | ||
|
|
a666a74a32 | ||
|
|
c285120ff4 | ||
|
|
dbd2890120 | ||
|
|
a5db46cdc5 | ||
|
|
765cf9b96a | ||
|
|
efe7952869 | ||
|
|
9e434de285 | ||
|
|
712fe2c250 | ||
|
|
5db5a2ed35 | ||
|
|
49c96e6fc8 | ||
|
|
d56c9a3f5a | ||
|
|
6c4c973ed8 | ||
|
|
a117303147 | ||
|
|
dbf248a508 | ||
|
|
56d75b14fa | ||
|
|
87311e2d7d | ||
|
|
bd63fb686d | ||
|
|
0f9a422d44 | ||
|
|
32d18b47f9 | ||
|
|
c618bf95fa | ||
|
|
a7bd70e334 | ||
|
|
d12bdc3745 | ||
|
|
08c8623951 | ||
|
|
d2ff7e3748 | ||
|
|
ea6452287b | ||
|
|
b1f7731563 | ||
|
|
be5ee8a6a3 | ||
|
|
21e5ac6b96 | ||
|
|
d67eca46e6 | ||
|
|
ebbd92fb7a | ||
|
|
60c4423ab7 | ||
|
|
82dbbc7f9f | ||
|
|
534307df87 | ||
|
|
6c4738fe82 | ||
|
|
6dcddb612e |
@@ -15,6 +15,9 @@
|
||||
- baseScale in NPCs has been removed from classes and presets, and in the entity it is replaced with hitboxScale and renderScale.
|
||||
- Added `EntityCallbacks` to `NPCEntity` and `PokemonEntity`. You can trigger custom callback types by using `[Entity].callbacks.process(...)`
|
||||
|
||||
### Fixes
|
||||
- Fixed Pokémon with a moving walk target frequently spinning in place as they re-calculate their path.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added a `behaviours` datapack folder which motivates the Behaviour Editor screen on NPCs and Pokémon.
|
||||
- Added "callback" support on PokemonEntity and NPCEntity that allows MoLang scripts to be executed in response to certain scenarios.
|
||||
|
||||
@@ -283,6 +283,15 @@
|
||||
- Revavroom
|
||||
- Bouffalant
|
||||
- Lickilicky
|
||||
- Blaziken
|
||||
- Rhyhorn
|
||||
- Rhydon
|
||||
- Rhyperior
|
||||
- Tauros
|
||||
- Tauros - Paldea Aqua
|
||||
- Tauros - Paldea Blaze
|
||||
- Tauros - Paldea Combat
|
||||
- Dewgong
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Cleffa
|
||||
@@ -456,6 +465,7 @@
|
||||
- Updated `EvolutionCompleteEvent` parameters to include the Source Pokemon that evolved.
|
||||
- Updated `HatchEggEvent.Post` to include the Pokemon that hatched.
|
||||
- Roseli Berry Trees now naturally generate in their preferred biomes.
|
||||
- Refactored dynamic lights compat to be more future proof. The dynamic light support is only tested with LambDynamicLights, on NeoForged use that mod in combination with Sinytra Connector
|
||||
|
||||
### Fixes
|
||||
- Fixed game crashing when removing national pokedex using datapacks
|
||||
@@ -669,6 +679,20 @@
|
||||
- Added `q.pokemon.is_busy` Returns whether the Pokémon is busy.
|
||||
- Added `q.pokemon.is_rideable` Returns whether the Pokémon is rideable.
|
||||
- Fixed `background` field and added `textColor` field for dialogues.
|
||||
- Added support to reload some data registries:
|
||||
- MoLang scripts
|
||||
- Callbacks
|
||||
- Spawn Detail Presets
|
||||
- Spawn Pools
|
||||
- Spawn Rules
|
||||
- Cosmetic Items
|
||||
- Dialogues
|
||||
- Fossils
|
||||
- Natural Materials
|
||||
- Action Effects
|
||||
- Mechanics
|
||||
- Unlockable Wallpapers
|
||||
- Starter Data
|
||||
|
||||
### Particles
|
||||
Added new/updated particles for the following moves:
|
||||
|
||||
@@ -31,6 +31,7 @@ repositories {
|
||||
maven(url = "${rootProject.projectDir}/deps")
|
||||
maven(url = "https://api.modrinth.com/maven")
|
||||
maven(url = "https://maven.neoforged.net/releases")
|
||||
maven(url = "https://maven.gegy.dev")
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
@@ -44,6 +45,12 @@ dependencies {
|
||||
modCompileOnly(libs.bundles.common.integrations.compileOnly) {
|
||||
isTransitive = false
|
||||
}
|
||||
// LambDynamicLights is handled differently because we need the Mojang-mappings version of it.
|
||||
modCompileOnly(libs.lambDynamicLights) {
|
||||
capabilities {
|
||||
requireCapability("dev.lambdaurora.lambdynamiclights:api-mojmap")
|
||||
}
|
||||
}
|
||||
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
|
||||
|
||||
@@ -1,102 +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.compat;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonEntities;
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||
import dev.lambdaurora.lambdynlights.LambDynLights;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
// Java class due to relying on entrypoint on Fabric side
|
||||
public class LambDynamicLightsCompat {
|
||||
|
||||
// This is all called on client side
|
||||
// These things are checked every tick so try to keep it as free as possible
|
||||
// That being said it's unlikely school Toshiba person is running dynamic lighting and shaders to enjoy this
|
||||
// Make sure not to call anything Fabric specific :)
|
||||
public static void hookCompat() {
|
||||
// Pokémon entities
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
CobblemonEntities.POKEMON,
|
||||
DynamicLightHandler.makeHandler(
|
||||
LambDynamicLightsCompat::resolvedPokemonLightLevel,
|
||||
pokemon -> false
|
||||
)
|
||||
);
|
||||
|
||||
// Shouldered Pokémon
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
EntityType.PLAYER,
|
||||
DynamicLightHandler.makeHandler(
|
||||
LambDynamicLightsCompat::resolvedPlayerLightLevel,
|
||||
player -> false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int resolvedPokemonLightLevel(PokemonEntity pokemon) {
|
||||
var underwater = !pokemon.level().getFluidState(BlockPos.containing(pokemon.getX(), pokemon.getEyeY(), pokemon.getZ())).isEmpty();
|
||||
|
||||
ItemStack item = pokemon.getShownItem();
|
||||
int itemLightLevel = item.isEmpty()?0:LambDynLights.getLuminanceFromItemStack(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
}
|
||||
|
||||
private static int resolvedPlayerLightLevel(Player player) {
|
||||
var underwater = !player.level().getFluidState(BlockPos.containing(player.getX(), player.getEyeY(), player.getZ())).isEmpty();
|
||||
final int leftShoulderLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft()), underwater);
|
||||
final int rightShoulderLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight()), underwater);
|
||||
final int itemLightLevel = customHeldItemLightLevel(player.getMainHandItem(), player.getOffhandItem());
|
||||
|
||||
return Math.max(itemLightLevel, Math.max(leftShoulderLightLevel, rightShoulderLightLevel));
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(form.getLightingData().getLightLevel());
|
||||
}
|
||||
|
||||
private static int extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||
if (shoulderData == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ItemStack item = shoulderData.getShownItem();
|
||||
int itemLightLevel = item.isEmpty() ? 0 :LambDynLights.getLuminanceFromItemStack(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(shoulderData.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
}
|
||||
|
||||
private static int customHeldItemLightLevel(ItemStack mainhand, ItemStack offhand) {
|
||||
return (mainhand.getItem() instanceof PokedexItem || offhand.getItem() instanceof PokedexItem) ? 13 : 0;
|
||||
}
|
||||
|
||||
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class CustomLuminance {
|
||||
protected static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(form.getLightingData().getLightLevel());
|
||||
}
|
||||
|
||||
protected static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightsContext;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightsInitializer;
|
||||
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
|
||||
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
|
||||
public class LambDynamicLightsInitializer implements DynamicLightsInitializer {
|
||||
public static final EntityLuminance.Type POKEMON_LUMINANCE = EntityLuminance.Type.registerSimple(
|
||||
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokemon"),
|
||||
PokemonLuminance.INSTANCE
|
||||
);
|
||||
public static final EntityLuminance.Type PLAYER_LUMINANCE = EntityLuminance.Type.registerSimple(
|
||||
ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "shoulder"),
|
||||
PlayerLuminance.INSTANCE
|
||||
);
|
||||
|
||||
@Override
|
||||
public void onInitializeDynamicLights(DynamicLightsContext context) {
|
||||
Cobblemon.LOGGER.info("Lamb Dynamic Lights compatibility enabled");
|
||||
|
||||
context.entityLightSourceManager().onRegisterEvent().register(ctx -> {
|
||||
ctx.register(EntityType.PLAYER, PlayerLuminance.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings({"removal", "UnstableApiUsage"})
|
||||
@Override
|
||||
public void onInitializeDynamicLights(ItemLightSourceManager itemLightSourceManager) {}
|
||||
}
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
|
||||
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
public final class PlayerLuminance extends CustomLuminance implements EntityLuminance {
|
||||
public static final PlayerLuminance INSTANCE = new PlayerLuminance();
|
||||
private static final TagKey<Item> POKEDEX = TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(Cobblemon.MODID, "pokedex"));
|
||||
|
||||
@Override
|
||||
public @NotNull Type type() {
|
||||
return LambDynamicLightsInitializer.PLAYER_LUMINANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Range(from = 0L, to = 15L) int getLuminance(@NotNull ItemLightSourceManager itemLightSourceManager, @NotNull Entity entity) {
|
||||
if (entity instanceof Player player) {
|
||||
final int shoulderLightLevel = shoulderLuminance(itemLightSourceManager, player);
|
||||
|
||||
final int itemLightLevel = player.isHolding(stack -> stack.is(POKEDEX)) ? 13 : 0;
|
||||
|
||||
return Math.max(shoulderLightLevel, itemLightLevel);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private @Range(from = 0L, to = 15L) static int shoulderLuminance(@NotNull ItemLightSourceManager itemLightSourceManager, @NotNull Player player) {
|
||||
final var leftShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft());
|
||||
final var rightShoulder = PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight());
|
||||
|
||||
if (leftShoulder == null && rightShoulder == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int leftShoulderLightLevel = extractShoulderLightLevel(leftShoulder, itemLightSourceManager, player.isUnderWater());
|
||||
final int rightShoulderLightLevel = extractShoulderLightLevel(rightShoulder, itemLightSourceManager, player.isUnderWater());
|
||||
return Math.max(leftShoulderLightLevel, rightShoulderLightLevel);
|
||||
}
|
||||
|
||||
private static int extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, @NotNull ItemLightSourceManager itemLightSourceManager, boolean underwater) {
|
||||
if (shoulderData == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ItemStack item = shoulderData.getShownItem();
|
||||
int itemLightLevel = item.isEmpty() ? 0 : itemLightSourceManager.getLuminance(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(shoulderData.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.compat.lambdynamiclights;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import dev.lambdaurora.lambdynlights.api.entity.luminance.EntityLuminance;
|
||||
import dev.lambdaurora.lambdynlights.api.item.ItemLightSourceManager;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
public final class PokemonLuminance extends CustomLuminance implements EntityLuminance {
|
||||
public static final PokemonLuminance INSTANCE = new PokemonLuminance();
|
||||
|
||||
private PokemonLuminance() {}
|
||||
|
||||
@Override
|
||||
public @NotNull Type type() {
|
||||
return LambDynamicLightsInitializer.POKEMON_LUMINANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Range(from = 0L, to = 15L) int getLuminance(
|
||||
@NotNull ItemLightSourceManager itemLightSourceManager,
|
||||
@NotNull Entity entity
|
||||
) {
|
||||
if (entity instanceof PokemonEntity pokemon) {
|
||||
boolean underwater = pokemon.isUnderWater();
|
||||
ItemStack item = pokemon.getShownItem();
|
||||
int itemLightLevel = item.isEmpty() ? 0 : itemLightSourceManager.getLuminance(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -31,14 +31,15 @@ public class AbstractClientPlayerMixin {
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
cir.setReturnValue(usageContext.getFovMultiplier());
|
||||
}
|
||||
} else {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
//Return custom fov mult
|
||||
cir.setReturnValue(ride.rideFovMult());
|
||||
// Return custom fov mult for riding
|
||||
cir.setReturnValue(ride.rideFovMult());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.model.AgeableListModel;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.Model;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* This mixin adds to the head of the renderToBuffer function and allows us to detect if it is a HumanoidModel and
|
||||
* is being rendered as part of a player in the world who is riding a PokemonEntity. If so we need to obey any
|
||||
* root animations that have been applied earlier.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since May 16, 2025
|
||||
*/
|
||||
@Mixin(AgeableListModel.class)
|
||||
public class AgeableListModelMixin {
|
||||
@Inject(method = "renderToBuffer", at = @At("HEAD"))
|
||||
private void cobblemon$renderToBuffer(
|
||||
PoseStack poseStack,
|
||||
VertexConsumer vertexConsumer,
|
||||
int packedLight,
|
||||
int packedOverlay,
|
||||
int colour,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
Model model = (Model) (Object) this;
|
||||
if (model instanceof HumanoidModel<?> && MountedPlayerRenderer.shouldApplyRootAnimation) {
|
||||
MountedPlayerRenderer.INSTANCE.animateRoot(poseStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-15
@@ -19,20 +19,17 @@ import net.minecraft.world.entity.LivingEntity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@Mixin(HumanoidModel.class)
|
||||
public class HumanoidModelMixin {
|
||||
@Unique HashMap<String, ModelPart> relevantPartsByName = new HashMap<>();
|
||||
|
||||
@Shadow @Final
|
||||
public ModelPart head;
|
||||
@Shadow @Final
|
||||
public ModelPart hat;
|
||||
@Shadow @Final
|
||||
public ModelPart rightArm;
|
||||
@Shadow @Final
|
||||
public ModelPart leftArm;
|
||||
@@ -40,6 +37,8 @@ public class HumanoidModelMixin {
|
||||
public ModelPart rightLeg;
|
||||
@Shadow @Final
|
||||
public ModelPart leftLeg;
|
||||
@Shadow @Final
|
||||
public ModelPart body;
|
||||
|
||||
@Inject(method = "setupAnim*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/geom/ModelPart;copyFrom(Lnet/minecraft/client/model/geom/ModelPart;)V", shift = At.Shift.BEFORE))
|
||||
public void cobblemon$animateRiders(
|
||||
@@ -51,19 +50,23 @@ public class HumanoidModelMixin {
|
||||
float headPitch,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
if (relevantPartsByName.isEmpty()) {
|
||||
relevantPartsByName.put("arm_left", leftArm);
|
||||
relevantPartsByName.put("arm_right", rightArm);
|
||||
relevantPartsByName.put("leg_left", leftLeg);
|
||||
relevantPartsByName.put("leg_right", rightLeg);
|
||||
relevantPartsByName.put("head", head);
|
||||
MountedPlayerRenderer.shouldApplyRootAnimation = false;
|
||||
|
||||
if (MountedPlayerRenderer.relevantPartsByName.size() <= 1) {
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_left", leftArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("arm_right", rightArm);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_left", leftLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("leg_right", rightLeg);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("head", head);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("hat", hat);
|
||||
MountedPlayerRenderer.relevantPartsByName.put("torso", body);
|
||||
}
|
||||
|
||||
Entity vehicle = entity.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && entity instanceof OrientationControllable) {
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRotateRiderHead(settings, state, pokemonEntity);
|
||||
});
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) ->
|
||||
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
|
||||
);
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
@@ -76,7 +79,8 @@ public class HumanoidModelMixin {
|
||||
|
||||
if (!(entity instanceof AbstractClientPlayer player)) return;
|
||||
|
||||
MountedPlayerRenderer.INSTANCE.animate(pokemonEntity, player, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
MountedPlayerRenderer.shouldApplyRootAnimation = true;
|
||||
MountedPlayerRenderer.INSTANCE.animate((HumanoidModel<AbstractClientPlayer>)(Object)this, pokemonEntity, player, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,6 +174,16 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
return this.cobblemon$isDoubleJumping;
|
||||
}
|
||||
|
||||
@Inject(method = "isHandsBusy", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$isHandsBusy(CallbackInfoReturnable<Boolean> cir) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
cir.setReturnValue(seat.getHandsBusy());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
|
||||
@@ -117,6 +117,8 @@ public abstract class MouseHandlerMixin {
|
||||
@Local(argsOnly = true) double d,
|
||||
@Local(argsOnly = true) double movementTime
|
||||
) {
|
||||
boolean returnValue = true;
|
||||
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
this.smoothTurnY.reset();
|
||||
@@ -127,7 +129,7 @@ public abstract class MouseHandlerMixin {
|
||||
var sensitivity = Mth.lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
var yRotationFlip = this.minecraft.options.invertYMouse().get() ? -1 : 1;
|
||||
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity * yRotationFlip));
|
||||
return false;
|
||||
returnValue = false;
|
||||
}
|
||||
|
||||
// Clamp player rotation if riding and the vehicle demands it
|
||||
@@ -143,35 +145,33 @@ public abstract class MouseHandlerMixin {
|
||||
pitchSmoother.reset();
|
||||
rollSmoother.reset();
|
||||
yawSmoother.reset();
|
||||
return true;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
//Send mouse input to be interpreted into rotation
|
||||
//deltas by the ride controller
|
||||
// Send mouse input to be interpreted into rotation
|
||||
// deltas by the ride controller
|
||||
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
|
||||
|
||||
//Perform Rotation using mouse influenced rotation deltas.
|
||||
// Perform Rotation using mouse influenced rotation deltas.
|
||||
controllable.getOrientationController().rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
);
|
||||
|
||||
//Gather and apply the current rotation deltas
|
||||
// Gather and apply the current rotation deltas
|
||||
var angRot = cobblemon$getAngularVelocity(movementTime);
|
||||
|
||||
//Apply smoothing if requested by the controller.
|
||||
//This Might be best if done by the controller itself?
|
||||
if(cobblemon$shouldUseAngVelSmoothing())
|
||||
{
|
||||
// Apply smoothing if requested by the controller.
|
||||
// This Might be best if done by the controller itself?
|
||||
if(cobblemon$shouldUseAngVelSmoothing()) {
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
controllable.getOrientationController().rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
//Otherwise simply apply the smoothing
|
||||
else
|
||||
{
|
||||
// Otherwise simply apply the smoothing
|
||||
else {
|
||||
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -26,10 +26,10 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
.networkSynchronized(PokemonItemComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val HELD_ITEM_REP: DataComponentType<HeldItemCapableComponent> = DataComponentType.builder<HeldItemCapableComponent>()
|
||||
.persistent(HeldItemCapableComponent.CODEC)
|
||||
.networkSynchronized(HeldItemCapableComponent.PACKET_CODEC)
|
||||
.build()
|
||||
val HELD_ITEM_EFFECT: DataComponentType<HeldItemEffectComponent> = create("held_item_effect", DataComponentType.builder<HeldItemEffectComponent>()
|
||||
.persistent(HeldItemEffectComponent.CODEC)
|
||||
.networkSynchronized(HeldItemEffectComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val BAIT: DataComponentType<RodBaitComponent> = create("bait", DataComponentType.builder<RodBaitComponent>()
|
||||
.persistent(RodBaitComponent.CODEC)
|
||||
@@ -86,6 +86,7 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ingredient"), INGREDIENT)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:mob_effects"), MOB_EFFECTS)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:held_item_effect"), HELD_ITEM_EFFECT)
|
||||
}
|
||||
|
||||
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonAvoidTargetData
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonWanderControl
|
||||
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
@@ -58,7 +57,6 @@ object CobblemonMemories {
|
||||
/** how many are following me rn? */
|
||||
val HERD_SIZE = register<Int>("herd_size") // Don't bother saving it, we'll try to keep count roughly.
|
||||
val ATTACK_TARGET_DATA = register<CobblemonAttackTargetData>("attack_target_data") // This is used to store additional information about the attack target, such as when to give up pursuit.
|
||||
val AVOID_TARGET_DATA = register<CobblemonAvoidTargetData>("avoid_target_data") // This is used to store additional information about the avoid target, such as how fast to move.
|
||||
val WANDER_CONTROL = register<CobblemonWanderControl>("wander_control")
|
||||
val DISABLE_WALK_TO_WANTED_ITEM = register<Boolean>("disable_walk_to_wanted_item")
|
||||
val TIME_TRYING_TO_REACH_WANTED_ITEM = register<Int>("time_trying_to_wanted_item")
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.client.net.OpenBehaviourEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.CalculateSeatPositionsHandler
|
||||
import com.cobblemon.mod.common.client.net.OpenBehaviourEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||
import com.cobblemon.mod.common.client.net.animation.PlayPosableAnimationHandler
|
||||
@@ -20,7 +20,6 @@ import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandl
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
|
||||
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.PokeSnackBlockParticlesHandler
|
||||
@@ -65,8 +64,8 @@ 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.CalculateSeatPositionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
|
||||
@@ -171,11 +170,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.SetItemHiddenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
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
|
||||
@@ -224,11 +223,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.SetItemHiddenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
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.starter.RequestStarterScreenHandler
|
||||
@@ -390,7 +389,6 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler))
|
||||
list.add(PacketRegisterInfo(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(GlobalSpeciesFeatureSyncPacket.ID, GlobalSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
+7
-22
@@ -20,8 +20,6 @@ import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
/**
|
||||
* This is used in the AI system to store optional additional information about the attack target,
|
||||
@@ -43,21 +41,15 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
class CobblemonAttackTargetData(
|
||||
/** An expression that returns false when the target is no longer worth attacking. */
|
||||
var shouldContinue: Expression = "true".asExpression(),
|
||||
var dealtHitsUntilDisengage: Int = -1, // -1 means no limit
|
||||
var disengageAction: (entity: LivingEntity) -> Unit = ::defaultDisengage
|
||||
var hitsUntilDisengage: Int = -1, // -1 means no limit
|
||||
var disengageAction: (entity: Entity) -> Unit = {}
|
||||
) {
|
||||
companion object {
|
||||
fun defaultDisengage(entity: LivingEntity) {
|
||||
entity.brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
entity.brain.updateActivityFromSchedule(entity.level().dayTime, entity.level().gameTime)
|
||||
}
|
||||
}
|
||||
val struct = ObjectValue<CobblemonAttackTargetData>(this).also {
|
||||
it.addFunction("dealt_hits_until_disengage") { DoubleValue(dealtHitsUntilDisengage.toDouble()) }
|
||||
it.addFunction("set_dealt_hits_until_disengage") { params ->
|
||||
it.addFunction("hits_until_disengage") { DoubleValue(hitsUntilDisengage.toDouble()) }
|
||||
it.addFunction("set_hits_until_disengage") { params ->
|
||||
val value = params.getDouble(0)
|
||||
dealtHitsUntilDisengage = value.toInt()
|
||||
DoubleValue(dealtHitsUntilDisengage.toDouble())
|
||||
hitsUntilDisengage = value.toInt()
|
||||
DoubleValue(hitsUntilDisengage.toDouble())
|
||||
}
|
||||
it.addFunction("set_disengage_action") { params ->
|
||||
val script = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
@@ -72,15 +64,8 @@ class CobblemonAttackTargetData(
|
||||
}
|
||||
DoubleValue.ONE
|
||||
}
|
||||
it.addFunction("reset") {
|
||||
shouldContinue = "true".asExpression()
|
||||
dealtHitsUntilDisengage = -1
|
||||
disengageAction = ::defaultDisengage
|
||||
DoubleValue.ONE
|
||||
}
|
||||
it.addFunction("unset_disengage_action") { params ->
|
||||
disengageAction = ::defaultDisengage
|
||||
disengageAction = {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +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.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.util.getDoubleOrNull
|
||||
|
||||
class CobblemonAvoidTargetData {
|
||||
var walkSpeed: Float? = null
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue<CobblemonAvoidTargetData>(this).also {
|
||||
it.addFunction("walk_speed") { DoubleValue(walkSpeed) }
|
||||
it.addFunction("set_walk_speed") { walkSpeed = it.getDoubleOrNull(0)?.toFloat() }
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.util.getBooleanOrNull
|
||||
import com.cobblemon.mod.common.util.getDoubleOrNull
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
|
||||
/**
|
||||
* Used to maintain some settings around how the entity should wander this tick. The idea is you
|
||||
@@ -29,8 +30,7 @@ class CobblemonWanderControl(
|
||||
var allowWater: Boolean = false,
|
||||
var allowAir: Boolean = false,
|
||||
var pathCooldownTicks: Int = 20 * 5, // Used to mitigate the cost of pathfinding.
|
||||
var speedMultiplier: Float = 1F,
|
||||
var wanderChance: Float? = null
|
||||
var wanderSpeed: Float = 0.35F,
|
||||
) {
|
||||
class WanderCenter(val x: Number, val y: Number, val z: Number, val minRange: Float, val maxRange: Float)
|
||||
|
||||
@@ -46,7 +46,7 @@ class CobblemonWanderControl(
|
||||
.addFunction("allow_water") { if (allowWater) 1.0 else 0.0 }
|
||||
.addFunction("allow_air") { if (allowAir) 1.0 else 0.0 }
|
||||
.addFunction("path_cooldown_ticks") { pathCooldownTicks.toDouble() }
|
||||
.addFunction("speed_multiplier") { speedMultiplier }
|
||||
.addFunction("wander_speed") { wanderSpeed }
|
||||
.addFunction("set_center") { params ->
|
||||
if (params.params.size < 3) {
|
||||
throw IllegalArgumentException("set_center requires at least 3 parameters: x, y, z")
|
||||
@@ -69,19 +69,15 @@ class CobblemonWanderControl(
|
||||
.addFunction("set_allow_water") { params -> allowWater = params.getBooleanOrNull(0) ?: false }
|
||||
.addFunction("set_allow_air") { params -> allowAir = params.getBooleanOrNull(0) ?: false }
|
||||
.addFunction("set_path_cooldown_ticks") { params -> pathCooldownTicks = params.getDoubleOrNull(0)?.toInt() ?: (20 * 5) }
|
||||
.addFunction("set_speed_multiplier") { params -> speedMultiplier = params.getDoubleOrNull(0)?.toFloat() ?: 0.35F }
|
||||
.addFunction("set_wander_chance") { params ->
|
||||
wanderChance = params.getDoubleOrNull(0)?.toFloat()
|
||||
}
|
||||
.addFunction("set_wander_speed") { params -> wanderSpeed = params.getDoubleOrNull(0)?.toFloat() ?: 0.35F }
|
||||
.addFunction("reset") {
|
||||
center = null
|
||||
allowLand = false
|
||||
allowWater = false
|
||||
allowAir = false
|
||||
pathCooldownTicks = 20 * 5
|
||||
speedMultiplier = 1F
|
||||
wanderSpeed = 0.35F
|
||||
maxAttempts = 4
|
||||
wanderChance = null
|
||||
}
|
||||
|
||||
fun isSuitable(position: BlockPos): Boolean {
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ class FindAirTaskConfig : SingleTaskConfig {
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (!entity.getIsSubmerged()) {
|
||||
if (!entity.getIsSubmerged() || entity.isInLava) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ class GoToLandTaskConfig : SingleTaskConfig {
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (!entity.isInLiquid) {
|
||||
if (!entity.isInWater) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
|
||||
-87
@@ -1,87 +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.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.EntityCallbacks
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
|
||||
/**
|
||||
* Frequently checks a diff on the visibility of entities around the given entity so EntityCallbacks can be triggered.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since August 7th, 2025
|
||||
*/
|
||||
class NotifyAboutEntityVisibilityTaskConfig : SingleTaskConfig {
|
||||
val ticksBetweenChecks: ExpressionOrEntityVariable = Either.left("20".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(ticksBetweenChecks).asVariables()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is MoLangScriptingEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
val ticksBetweenChecks = ticksBetweenChecks.resolveInt(behaviourConfigurationContext.runtime)
|
||||
|
||||
behaviourConfigurationContext.addMemories(MemoryModuleType.NEAREST_LIVING_ENTITIES)
|
||||
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
|
||||
|
||||
return object : Behavior<LivingEntity>(mapOf(MemoryModuleType.NEAREST_LIVING_ENTITIES to MemoryStatus.VALUE_PRESENT), Int.MAX_VALUE) {
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long) = true
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity) = true
|
||||
|
||||
// Buffer of known entities
|
||||
val knownEntities = mutableListOf<LivingEntity>()
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
if (gameTime % ticksBetweenChecks != 0L) {
|
||||
return
|
||||
}
|
||||
|
||||
val visibleEntities = owner.getBrain().getMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES)
|
||||
.orElse(emptyList<LivingEntity>())
|
||||
.filter { it.isAlive }
|
||||
|
||||
val newEntities = visibleEntities.filterNot { it in knownEntities }
|
||||
val removedEntities = knownEntities.filterNot { it in visibleEntities }
|
||||
|
||||
newEntities.forEach {
|
||||
entity.callbacks.process(
|
||||
type = EntityCallbacks.SAW_ENTITY,
|
||||
functions = mapOf("other_entity" to { _ -> it.asMostSpecificMoLangValue() })
|
||||
)
|
||||
}
|
||||
|
||||
removedEntities.forEach {
|
||||
entity.callbacks.process(
|
||||
type = EntityCallbacks.LOST_ENTITY,
|
||||
functions = mapOf("other_entity" to { _ -> it.asMostSpecificMoLangValue() })
|
||||
)
|
||||
}
|
||||
|
||||
knownEntities.clear()
|
||||
knownEntities.addAll(visibleEntities)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,6 @@ interface TaskConfig {
|
||||
cobblemonResource("target_entity") to TargetEntityTaskConfig::class.java,
|
||||
cobblemonResource("memory_aspect") to MemoryAspectTaskConfig::class.java,
|
||||
cobblemonResource("activity_change") to ActivityChangeTaskConfig::class.java,
|
||||
cobblemonResource("notify_about_entity_visibility") to NotifyAboutEntityVisibilityTaskConfig::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+54
-26
@@ -14,6 +14,8 @@ import com.cobblemon.mod.common.api.ai.CobblemonWanderControl
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.OmniPathingEntity
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonRandomSurfacePos
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonWalkTarget
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
@@ -26,6 +28,7 @@ import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorUtils
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
@@ -41,24 +44,27 @@ class WanderTaskConfig : SingleTaskConfig {
|
||||
}
|
||||
|
||||
val condition = booleanVariable(WANDER, "wanders", true).asExpressible()
|
||||
val wanderChance = numberVariable(WANDER, "wander_chance", 1/(20 * 6F)).asExpressible()
|
||||
val wanderChance = numberVariable(WANDER, "wander_chance", 1 / (20 * 6F)).asExpressible()
|
||||
val horizontalRange = numberVariable(WANDER, "horizontal_wander_range", 10).asExpressible()
|
||||
val verticalRange = numberVariable(WANDER, "vertical_wander_range", 5).asExpressible()
|
||||
val speedMultiplier = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
val avoidTargetingAir: ExpressionOrEntityVariable = Either.left("true".asExpression()) // Whether to avoid air blocks when wandering
|
||||
val speedMultiplier =
|
||||
numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
val avoidTargetingAir: ExpressionOrEntityVariable =
|
||||
Either.left("true".asExpression()) // Whether to avoid air blocks when wandering
|
||||
val minimumHeight: ExpressionOrEntityVariable = Either.left("0".asExpression()) // Height off the ground
|
||||
val maximumHeight: ExpressionOrEntityVariable = Either.left("-1".asExpression()) // Height off the ground
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition,
|
||||
wanderChance,
|
||||
horizontalRange,
|
||||
verticalRange,
|
||||
speedMultiplier,
|
||||
avoidTargetingAir,
|
||||
minimumHeight,
|
||||
maximumHeight
|
||||
).asVariables()
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) =
|
||||
listOf(
|
||||
condition,
|
||||
wanderChance,
|
||||
horizontalRange,
|
||||
verticalRange,
|
||||
speedMultiplier,
|
||||
avoidTargetingAir,
|
||||
minimumHeight,
|
||||
maximumHeight
|
||||
).asVariables()
|
||||
|
||||
private fun applyHeightConstraints(
|
||||
pos: BlockPos,
|
||||
@@ -77,7 +83,7 @@ class WanderTaskConfig : SingleTaskConfig {
|
||||
(1..MAX_LOOK_DOWN_DISTANCE).firstOrNull {
|
||||
val newPos = pos.below(it)
|
||||
if (!world.getBlockState(newPos).isAir) {
|
||||
return@firstOrNull true
|
||||
return@firstOrNull true
|
||||
} else if (newPos.y <= world.minBuildHeight) {
|
||||
// Don't adjust downward into the void (Mostly if we're in the end)
|
||||
// This doesn't stop fliers from wandering off end islands,
|
||||
@@ -126,18 +132,17 @@ class WanderTaskConfig : SingleTaskConfig {
|
||||
it.registered(CobblemonMemories.WANDER_CONTROL)
|
||||
).apply(it) { walkTarget, lookTarget, pathCooldown, wanderControl ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || entity.isUnderWater) {
|
||||
if (entity !is PathfinderMob || (entity.isUnderWater && !(entity.canBreatheUnderwater() && !((entity as OmniPathingEntity).canSwimInWater())))) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val wanderControl = it.tryGet(wanderControl).orElse(null) ?: CobblemonWanderControl()
|
||||
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val avoidsTargetingAir = avoidTargetingAir.resolveBoolean(mainThreadRuntime)
|
||||
val wanderChance = wanderControl.wanderChance ?: mainThreadRuntime.resolveFloat(wanderChanceExpression)
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance || !wanderControl.allowLand) {
|
||||
val wanderChance = mainThreadRuntime.resolveFloat(wanderChanceExpression)
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
pathCooldown.setWithExpiry(true, wanderControl.pathCooldownTicks.toLong())
|
||||
val minimumHeight = minimumHeight.resolveInt(mainThreadRuntime)
|
||||
val maximumHeight = maximumHeight.resolveInt(mainThreadRuntime)
|
||||
@@ -157,14 +162,28 @@ class WanderTaskConfig : SingleTaskConfig {
|
||||
maximumHeight,
|
||||
minimumHeight
|
||||
)
|
||||
} else if (entity.isUnderWater && entity.canBreatheUnderwater() && !((entity as OmniPathingEntity).canSwimInWater())) {
|
||||
BehaviorUtils.getRandomSwimmablePos(
|
||||
entity,
|
||||
horizontalRange.resolveInt(mainThreadRuntime),
|
||||
verticalRange.resolveInt(mainThreadRuntime)
|
||||
)
|
||||
} else if (entity is OmniPathingEntity && (entity.canWalkOnWater() || entity.canWalkOnLava())) {
|
||||
CobblemonRandomSurfacePos.getPos(
|
||||
entity,
|
||||
horizontalRange.resolveInt(mainThreadRuntime),
|
||||
verticalRange.resolveInt(mainThreadRuntime)
|
||||
)
|
||||
} else {
|
||||
LandRandomPos.getPos(
|
||||
entity,
|
||||
horizontalRange.resolveInt(mainThreadRuntime),
|
||||
verticalRange.resolveInt(mainThreadRuntime)
|
||||
)
|
||||
LandRandomPos.getPos(
|
||||
entity,
|
||||
horizontalRange.resolveInt(mainThreadRuntime),
|
||||
verticalRange.resolveInt(mainThreadRuntime)
|
||||
)
|
||||
} ?: continue
|
||||
|
||||
if (targetVec == null) continue
|
||||
|
||||
pos = applyHeightConstraints(
|
||||
pos = BlockPos.containing(targetVec),
|
||||
minimumHeight = minimumHeight,
|
||||
@@ -180,10 +199,19 @@ class WanderTaskConfig : SingleTaskConfig {
|
||||
walkTarget.set(
|
||||
CobblemonWalkTarget(
|
||||
pos = pos,
|
||||
speedModifier = speedMultiplier.resolveFloat(mainThreadRuntime) * wanderControl.speedMultiplier,
|
||||
speedModifier = speedMultiplier.resolveFloat(mainThreadRuntime),
|
||||
completionRange = 0,
|
||||
nodeTypeFilter = { nodeType -> nodeType !in listOf(PathType.WATER, PathType.WATER_BORDER) },
|
||||
destinationNodeTypeFilter = { nodeType -> !avoidsTargetingAir || nodeType !in listOf(PathType.OPEN) }
|
||||
nodeTypeFilter = { nodeType ->
|
||||
entity.canBreatheUnderwater() || nodeType !in listOf(
|
||||
PathType.WATER,
|
||||
PathType.WATER_BORDER
|
||||
)
|
||||
},
|
||||
destinationNodeTypeFilter = { nodeType ->
|
||||
!avoidsTargetingAir || nodeType !in listOf(
|
||||
PathType.OPEN
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
lookTarget.set(BlockPosTracker(pos.toVec3d().add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
+2
-2
@@ -78,7 +78,7 @@ class WaterWanderTaskConfig : SingleTaskConfig {
|
||||
}
|
||||
|
||||
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val wanderChance = wanderControl.wanderChance ?: mainThreadRuntime.resolveFloat(wanderChanceExpression)
|
||||
val wanderChance = mainThreadRuntime.resolveFloat(wanderChanceExpression)
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) {
|
||||
return@Trigger false
|
||||
}
|
||||
@@ -104,7 +104,7 @@ class WaterWanderTaskConfig : SingleTaskConfig {
|
||||
CobblemonWalkTarget(
|
||||
pos = pos,
|
||||
nodeTypeFilter = { it == PathType.WATER || it == PathType.WATER_BORDER },
|
||||
speedModifier = speedMultiplier.resolveFloat(mainThreadRuntime) * wanderControl.speedMultiplier,
|
||||
speedModifier = speedMultiplier.resolveFloat(mainThreadRuntime),
|
||||
completionRange = 0
|
||||
)
|
||||
)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking
|
||||
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.util.StringRepresentable
|
||||
|
||||
/**
|
||||
@@ -18,16 +17,16 @@ import net.minecraft.util.StringRepresentable
|
||||
* @author Licious
|
||||
* @since November 28th, 2022
|
||||
*/
|
||||
enum class Flavour(val colour: Int, val chatFormatting: ChatFormatting): StringRepresentable {
|
||||
SPICY(0x00FF00, ChatFormatting.RED),
|
||||
DRY(0xFF0000, ChatFormatting.DARK_AQUA),
|
||||
SWEET(0x0000FF, ChatFormatting.LIGHT_PURPLE),
|
||||
BITTER(0xFFFF00, ChatFormatting.GREEN),
|
||||
SOUR(0xFF00FF, ChatFormatting.YELLOW),
|
||||
MILD(0xFF00FF, ChatFormatting.DARK_PURPLE);
|
||||
enum class Flavour(val colour: Int): StringRepresentable {
|
||||
SPICY(0xFA795E),
|
||||
DRY(0x65AFF3),
|
||||
SWEET(0xFF82CF),
|
||||
BITTER(0x77C96A),
|
||||
SOUR(0xF3D465),
|
||||
MILD(0x9D99BF);
|
||||
|
||||
override fun getSerializedName() = name
|
||||
companion object {
|
||||
val CODEC = StringRepresentable.fromEnum<Flavour> { Flavour.entries.toTypedArray() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,13 @@ import net.minecraft.resources.ResourceLocation
|
||||
* @since August 5th, 2022
|
||||
*/
|
||||
interface DataProvider {
|
||||
|
||||
/**
|
||||
* Registers a [DataRegistry] to listen for updates.
|
||||
* The updates will automatically happen on the correct sides based on [DataRegistry.type].
|
||||
*
|
||||
* @param registry The [DataRegistry] being registered.
|
||||
*/
|
||||
fun <T : DataRegistry> register(registry: T): T
|
||||
fun <T : DataRegistry> register(registry: T, reloadable: Boolean): T
|
||||
|
||||
/**
|
||||
* Attempts to find a [DataRegistry] with the given [ResourceLocation].
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.item
|
||||
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
import java.io.File
|
||||
|
||||
object HeldItems : DataRegistry {
|
||||
|
||||
override val id = cobblemonResource("held_items")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<HeldItems>()
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
|
||||
// val heldItems = PrioritizedList<BagItemLike>()
|
||||
internal val heldItemsScripts = mutableMapOf<String, String>() // showdown item ID to JavaScript
|
||||
val showdownItems = hashSetOf<String>()
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
heldItemsScripts.clear()
|
||||
ShowdownService.service.resetRegistryData("heldItem")
|
||||
manager.listResources("held_items") { it.path.endsWith(".js") }.forEach { (identifier, resource) ->
|
||||
resource.open().use { stream ->
|
||||
stream.bufferedReader().use { reader ->
|
||||
val resolvedIdentifier = ResourceLocation.fromNamespaceAndPath(identifier.namespace, File(identifier.path).nameWithoutExtension)
|
||||
val js = reader.readText()
|
||||
heldItemsScripts[resolvedIdentifier.path] = js
|
||||
}
|
||||
}
|
||||
}
|
||||
ShowdownService.service.sendRegistryData(heldItemsScripts, "heldItem")
|
||||
|
||||
val itemsJson = ShowdownService.service.getRegistryData("heldItem")
|
||||
for (i in 0 until itemsJson.size()) {
|
||||
val jsItem = itemsJson[i].asJsonObject
|
||||
showdownItems += jsItem.get("id").asString
|
||||
}
|
||||
|
||||
CobblemonHeldItemManager.load()
|
||||
|
||||
this.observable.emit(this)
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.MoParams
|
||||
import com.bedrockk.molang.runtime.struct.ArrayStruct
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
@@ -24,8 +25,6 @@ import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonBlockPosTracker
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonAttackTargetData
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonAvoidTargetData
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonWanderControl
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
@@ -349,7 +348,10 @@ object MoLangFunctions {
|
||||
val b = format.parse(dateB)
|
||||
DoubleValue(a.after(b))
|
||||
},
|
||||
"create_simple_party_provider" to java.util.function.Function { SimplePartyProvider().struct },
|
||||
"create_simple_party_provider" to java.util.function.Function { params ->
|
||||
val partyProvider = SimplePartyProvider()
|
||||
return@Function partyProvider.struct
|
||||
},
|
||||
"create_pickup_item" to java.util.function.Function { params ->
|
||||
val item = params.getOrNull<MoValue>(0)?.asString()?.let(ObtainableItemCondition::parseFromString)
|
||||
val pickupPriority = params.getIntOrNull(1) ?: 0
|
||||
@@ -362,7 +364,6 @@ object MoLangFunctions {
|
||||
{ worldHolder ->
|
||||
val world = worldHolder.value()
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("id") { StringValue(world.dimension().location().toString()) }
|
||||
map.put("is_time_of_day") { params ->
|
||||
val timeOfDay = TimeRange.timeRanges[params.getString(0).lowercase()]
|
||||
?: return@put DoubleValue.ZERO
|
||||
@@ -806,13 +807,6 @@ object MoLangFunctions {
|
||||
val source = DamageSource(entity.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolder(DamageTypes.GENERIC).get())
|
||||
entity.hurt(source, amount.toFloat())
|
||||
}
|
||||
map.put("damage_source") { params ->
|
||||
val registry = entity.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE)
|
||||
val type = params.getStringOrNull(0)?.asIdentifierDefaultingNamespace()?.let(registry::getHolder)
|
||||
?: registry.getHolder(DamageTypes.GENERIC)
|
||||
val damageSource = DamageSource(type.get(), entity)
|
||||
return@put damageSource.asMoLangValue()
|
||||
}
|
||||
map.put("distance_to_owner") {
|
||||
if (entity !is TamableAnimal) {
|
||||
return@put DoubleValue.ZERO
|
||||
@@ -936,10 +930,6 @@ object MoLangFunctions {
|
||||
map.put("is_on_fire") { _ -> DoubleValue(entity.isOnFire) }
|
||||
map.put("is_invisible") { _ -> DoubleValue(entity.isInvisible) }
|
||||
map.put("is_riding") { _ -> DoubleValue(entity.isPassenger) }
|
||||
map.put("distance_to_entity") { params ->
|
||||
val otherEntity = params.get<MoValue>(0) as? ObjectValue<Entity> ?: return@put DoubleValue.ZERO
|
||||
return@put DoubleValue(entity.distanceTo(otherEntity.obj))
|
||||
}
|
||||
map.put("distance_to_pos") { params ->
|
||||
val x = params.getDouble(0)
|
||||
val y = params.getDouble(1)
|
||||
@@ -1073,19 +1063,7 @@ object MoLangFunctions {
|
||||
}
|
||||
)
|
||||
|
||||
val damageSourceFunctions: MutableList<(DamageSource) -> java.util.HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
{ source ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("direct_entity") { source.directEntity?.asMostSpecificMoLangValue() ?: DoubleValue.ZERO }
|
||||
map.put("entity") { source.entity?.asMostSpecificMoLangValue() ?: DoubleValue.ZERO }
|
||||
map.put("is_food_exhaustion") { DoubleValue(source.foodExhaustion) }
|
||||
map.put("is_direct") { DoubleValue(source.isDirect) }
|
||||
map.put("type") { StringValue(source.typeHolder().unwrapKey().get().location().toString()) }
|
||||
return@mutableListOf map
|
||||
}
|
||||
)
|
||||
|
||||
val livingEntityFunctions: MutableList<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
val livingEntityFunctions: MutableList<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ entity ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("is_player") { _ -> DoubleValue(entity is Player) }
|
||||
@@ -1127,23 +1105,6 @@ object MoLangFunctions {
|
||||
val amount = params.getDouble(0)
|
||||
entity.heal(amount.toFloat())
|
||||
}
|
||||
map.put("reset_activity") { _ ->
|
||||
entity.brain.updateActivityFromSchedule(entity.level().dayTime, entity.level().gameTime)
|
||||
DoubleValue.ONE
|
||||
}
|
||||
map.put("activity") { _ ->
|
||||
return@put entity.brain.activeNonCoreActivity.map { StringValue(it.name) }.orElse(null) ?: DoubleValue.ZERO
|
||||
}
|
||||
map.put("set_activity") { params ->
|
||||
val activityId = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val activity = BuiltInRegistries.ACTIVITY.get(activityId)
|
||||
if (activity != null) {
|
||||
entity.brain.setActiveActivityIfPossible(activity)
|
||||
return@put DoubleValue.ONE
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("is_looking_at") { params ->
|
||||
val targetEntity = params.get<MoValue>(0)
|
||||
val maxDistance = params.getDoubleOrNull(1)?.toFloat() ?: 2.0F
|
||||
@@ -1170,26 +1131,6 @@ object MoLangFunctions {
|
||||
val brain = entity.brain
|
||||
brain.setMemoryWithExpiry(MemoryModuleType.LOOK_TARGET, CobblemonBlockPosTracker(Vec3(x, y, z), flags.toSet()), duration.toLong())
|
||||
}
|
||||
map.put("is_doing_activity") { params ->
|
||||
val identifiers = params.params.map { it.asString().asIdentifierDefaultingNamespace(namespace = "minecraft") }
|
||||
val activities = identifiers.mapNotNull(BuiltInRegistries.ACTIVITY::get)
|
||||
if (activities.isNotEmpty()) {
|
||||
return@put DoubleValue(activities.any(entity.brain::isActive))
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("get_attack_target_data_memory") {
|
||||
val value = entity.brain.getMemorySafely(CobblemonMemories.ATTACK_TARGET_DATA).orElse(null)
|
||||
?: CobblemonAttackTargetData()
|
||||
if (
|
||||
!entity.brain.checkMemory(CobblemonMemories.ATTACK_TARGET_DATA, MemoryStatus.VALUE_PRESENT)
|
||||
&& entity.brain.checkMemory(CobblemonMemories.ATTACK_TARGET_DATA, MemoryStatus.REGISTERED)
|
||||
) {
|
||||
entity.brain.setMemory(CobblemonMemories.ATTACK_TARGET_DATA, value)
|
||||
}
|
||||
return@put value.struct
|
||||
}
|
||||
map.put("get_wander_control_memory") {
|
||||
val value = entity.brain.getMemorySafely(CobblemonMemories.WANDER_CONTROL).orElse(null)
|
||||
?: CobblemonWanderControl()
|
||||
@@ -1201,17 +1142,6 @@ object MoLangFunctions {
|
||||
}
|
||||
return@put value.struct
|
||||
}
|
||||
map.put("get_avoid_target_data_memory") {
|
||||
val value = entity.brain.getMemorySafely(CobblemonMemories.AVOID_TARGET_DATA).orElse(null)
|
||||
?: CobblemonAvoidTargetData()
|
||||
if (
|
||||
!entity.brain.checkMemory(CobblemonMemories.AVOID_TARGET_DATA, MemoryStatus.VALUE_PRESENT)
|
||||
&& entity.brain.checkMemory(CobblemonMemories.AVOID_TARGET_DATA, MemoryStatus.REGISTERED)
|
||||
) {
|
||||
entity.brain.setMemory(CobblemonMemories.AVOID_TARGET_DATA, value)
|
||||
}
|
||||
return@put value.struct
|
||||
}
|
||||
map.put("get_position_memory") { params ->
|
||||
val id = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val memoryType = BuiltInRegistries.MEMORY_MODULE_TYPE.get(id)
|
||||
@@ -1238,30 +1168,6 @@ object MoLangFunctions {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("get_entity_memory") { params ->
|
||||
val id = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val memoryType = BuiltInRegistries.MEMORY_MODULE_TYPE.get(id)
|
||||
if (entity.brain.checkMemory(memoryType, MemoryStatus.VALUE_PRESENT)) {
|
||||
val memory = entity.brain.getMemory(memoryType).get()
|
||||
return@put when (memory) {
|
||||
is Entity -> memory.asMostSpecificMoLangValue()
|
||||
else -> DoubleValue.ZERO
|
||||
}
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("set_entity_memory") { params ->
|
||||
val memory = params.getString(0).asIdentifierDefaultingNamespace().let(BuiltInRegistries.MEMORY_MODULE_TYPE::get) as MemoryModuleType<LivingEntity>
|
||||
val entityValue = (params.get<MoValue>(1) as? ObjectValue<*>)?.obj as? LivingEntity ?: return@put DoubleValue.ZERO
|
||||
val expiry = params.getIntOrNull(2) ?: -1
|
||||
if (expiry != -1) {
|
||||
entity.brain.setMemoryWithExpiry(memory, entityValue, expiry.toLong())
|
||||
} else {
|
||||
entity.brain.setMemory(memory, entityValue)
|
||||
}
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("set_uuid_memory") { params ->
|
||||
val memory = params.getString(0).asIdentifierDefaultingNamespace().let(BuiltInRegistries.MEMORY_MODULE_TYPE::get) as MemoryModuleType<UUID>
|
||||
val uuid = params.getString(1).asUUID ?: return@put DoubleValue.ZERO
|
||||
@@ -1308,18 +1214,6 @@ object MoLangFunctions {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("is_visible_entity") { params ->
|
||||
val otherEntity = params.get<ObjectValue<*>>(0)?.obj as? LivingEntity ?: return@put DoubleValue.ZERO
|
||||
val visibleMobs = entity.brain.getMemorySafely(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES).orElse(null)
|
||||
?: return@put DoubleValue.ZERO
|
||||
return@put DoubleValue(visibleMobs.contains(otherEntity))
|
||||
}
|
||||
map.put("is_nearby_entity") { params ->
|
||||
val otherEntity = params.get<ObjectValue<*>>(0)?.obj as? LivingEntity ?: return@put DoubleValue.ZERO
|
||||
val nearbyMobs = entity.brain.getMemorySafely(MemoryModuleType.NEAREST_LIVING_ENTITIES).orElse(null)
|
||||
?: return@put DoubleValue.ZERO
|
||||
return@put DoubleValue(nearbyMobs.contains(otherEntity))
|
||||
}
|
||||
if (entity is PathfinderMob) {
|
||||
map.put("walk_to") { params ->
|
||||
val x = params.getDouble(0)
|
||||
@@ -1358,6 +1252,15 @@ object MoLangFunctions {
|
||||
map.put("in_battle") { DoubleValue(npc.isInBattle()) }
|
||||
map.put("battles") { ArrayStruct(npc.battleIds.mapNotNull { BattleRegistry.getBattle(it)?.struct }.mapIndexed { index, value -> "$index" to value }.toMap()) }
|
||||
map.put("stop_battles") { _ -> npc.battleIds.forEach { BattleRegistry.getBattle(it)?.stop() } }
|
||||
map.put("is_doing_activity") { params ->
|
||||
val identifiers = params.params.map { it.asString().asIdentifierDefaultingNamespace(namespace = "minecraft") }
|
||||
val activities = identifiers.mapNotNull { identifier -> BuiltInRegistries.ACTIVITY.get(identifier) }
|
||||
if (activities.isNotEmpty()) {
|
||||
return@put DoubleValue(activities.any { activity -> npc.brain.isActive(activity) })
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("run_script_on_client") { params ->
|
||||
val world = npc.level()
|
||||
if (world is ServerLevel) {
|
||||
@@ -2568,15 +2471,6 @@ object MoLangFunctions {
|
||||
return value
|
||||
}
|
||||
|
||||
fun DamageSource.asMoLangValue(): ObjectValue<DamageSource> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.toString() }
|
||||
)
|
||||
value.addFunctions(damageSourceFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Different functions exist depending on the entity type, this tries to make the struct that's most specific to the type.
|
||||
*/
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.asin
|
||||
import kotlin.math.sign
|
||||
|
||||
@@ -113,7 +114,7 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
|
||||
fun applyGlobalPitch(deltaPitchDegrees: Float) = updateOrientation { original ->
|
||||
val currQuat = Quaternionf().setFromUnnormalized(original)
|
||||
val horzLeftVector = Vector3f(0.0f, this.upVector.y.sign, 0.0f).cross(this.forwardVector)
|
||||
val horzLeftVector = Vector3f(0.0f, -abs(this.upVector.y.sign), 0.0f).cross(this.forwardVector)
|
||||
// Avoid NaN issue when normalizing and the forwardVector and upVector are equal
|
||||
val pitchAxis = if (horzLeftVector.lengthSquared() < 0.01) this.leftVector else horzLeftVector
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ import com.cobblemon.mod.common.pokemon.ai.ObtainableItemConditionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonEvolutionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonPreEvolutionAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.common.collect.HashBasedTable
|
||||
@@ -158,8 +157,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
it.resetRegistryData("species")
|
||||
it.sendRegistryData(allShowdownSpecies(), "species")
|
||||
it.indicateSpeciesInitialized()
|
||||
// Reload this with the mod
|
||||
CobblemonHeldItemManager.load()
|
||||
Cobblemon.LOGGER.info("Loaded {} Pokémon species", this.speciesByIdentifier.size)
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import net.minecraft.world.entity.PlayerRideableJumping
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,8 @@ data class Seat(
|
||||
val locator: String?,
|
||||
val offset: Vec3?,
|
||||
val poseOffsets: MutableList<SeatPoseOffset>?,
|
||||
val poseAnimations: MutableList<SeatPoseAnimations>?
|
||||
val poseAnimations: MutableList<SeatPoseAnimations>?,
|
||||
val handsBusy: Boolean = false,
|
||||
) : Encodable {
|
||||
fun getOffset(poseType: PoseType) : Vec3 {
|
||||
return poseOffsets?.firstOrNull { poseType in it.poseTypes }?.offset ?: Vec3.ZERO
|
||||
@@ -40,6 +41,7 @@ data class Seat(
|
||||
buffer.writeNullable(poseAnimations) { _, v ->
|
||||
buffer.writeCollection(v) { _, animations -> animations.encode(buffer) }
|
||||
}
|
||||
buffer.writeBoolean(handsBusy)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -48,7 +50,8 @@ data class Seat(
|
||||
buffer.readNullable { buffer.readString() },
|
||||
buffer.readNullable { buffer.readVec3() },
|
||||
buffer.readNullable { buffer.readList { SeatPoseOffset.decode(buffer) } },
|
||||
buffer.readNullable { buffer.readList { SeatPoseAnimations.decode(buffer) } }
|
||||
buffer.readNullable { buffer.readList { SeatPoseAnimations.decode(buffer) } },
|
||||
buffer.readBoolean()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -10,10 +10,8 @@ package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* Represents static settings of a riding behaviour.
|
||||
@@ -27,10 +25,9 @@ interface RidingBehaviourSettings: Encodable, Decodable {
|
||||
val key: ResourceLocation
|
||||
val stats: MutableMap<RidingStat, IntRange>
|
||||
|
||||
fun calculate(stat: RidingStat, boosts: Int): Float {
|
||||
fun calculate(stat: RidingStat, boostAmount: Float): Float {
|
||||
val range = stats[stat] ?: return 0F
|
||||
val boostQuotient = boosts / 255F
|
||||
return range.first + (range.last - range.first) * boostQuotient
|
||||
return range.first + boostAmount
|
||||
}
|
||||
|
||||
fun hasStat(stat: RidingStat) = stats.containsKey(stat)
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ class RidingController(
|
||||
if (newTransition != null && behaviourSettings != null) {
|
||||
val newState = RidingBehaviours.get(behaviourSettings.key).createDefaultState(behaviourSettings)
|
||||
context?.let { newState.stamina.set(it.state.stamina.get(), forced = true) }
|
||||
context?.let { newState.rideVelocity.set(it.state.rideVelocity.get(), forced = true) }
|
||||
context = ActiveRidingContext(behaviourSettings.key, behaviourSettings, newState, newTransition)
|
||||
lastTransitionAge = entity.ticksLived
|
||||
} else {
|
||||
|
||||
+80
-30
@@ -21,18 +21,18 @@ import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.*
|
||||
|
||||
class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
@@ -50,7 +50,18 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.2 })
|
||||
|
||||
override fun isActive(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
//Need to check other fluids
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any false
|
||||
}
|
||||
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
|
||||
if (it.y.toDouble() == (vehicle.position().y)) {
|
||||
val blockState = vehicle.level().getBlockState(it.below())
|
||||
return@any !(!blockState.isAir && blockState.fluidState.isEmpty)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): PoseType {
|
||||
@@ -88,7 +99,10 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
if (cos(controller.roll.toRadians()) < 0.0) {
|
||||
val upsideDownRate = 1.0 / (2.0 * 20.0) // 2 seconds to max out upsideDown force
|
||||
state.currUpsideDownForce.set( min(1.0, state.currUpsideDownForce.get() + upsideDownRate * abs(cos(controller.roll.toRadians()))))
|
||||
} else { // Its right side up so reset it
|
||||
} else if (state.stamina.get() == 0.0f) { // checks stamina depletion and forces dive if depleted
|
||||
val upsideDownRate = 1.0 / (2.0 * 20.0) // 1 seconds to max out
|
||||
state.currUpsideDownForce.set( min(1.0, state.currUpsideDownForce.get() + upsideDownRate))
|
||||
} else { // Its right side up or has stamina so reset it
|
||||
state.currUpsideDownForce.set(0.0)
|
||||
}
|
||||
}
|
||||
@@ -149,8 +163,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
}
|
||||
|
||||
// The downward force used to encourage players to stop flying upside down.
|
||||
val extraDownwardForce = if(state.stamina.get() == 0.0f) -0.3
|
||||
else state.currUpsideDownForce.get().pow(2) * -0.3 // 6 blocks a second downward
|
||||
val extraDownwardForce = state.currUpsideDownForce.get().pow(2) * -0.3 // 6 blocks a second downward
|
||||
|
||||
val velocity = Vec3(state.rideVelocity.get().x , upForce + extraDownwardForce, forwardForce)
|
||||
return velocity
|
||||
@@ -275,18 +288,20 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
|
||||
val yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())).pow(2) * sin(Math.toRadians(controller.roll.toDouble())).sign
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble()))) * sqrt(RidingBehaviour.scaleToRange(state.rideVelocity.get().length(), 0.0, topSpeed))
|
||||
val yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())) //* sin(Math.toRadians(controller.roll.toDouble())).sign
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble())))// * sqrt(RidingBehaviour.scaleToRange(state.rideVelocity.get().length(), 0.0, topSpeed))
|
||||
|
||||
// Dampen yaw when upside down
|
||||
val yawDampen = (1 - abs(min(cos(controller.roll.toRadians()),0.0f)))
|
||||
val yawDampen = (1 - abs(min(cos(controller.roll.toRadians()),0.0f)).pow(2))
|
||||
controller.applyGlobalYaw(trueYawDelt.toFloat() * yawDampen)
|
||||
|
||||
// Correct orientation when at low speeds
|
||||
correctOrientation(settings, state, vehicle, controller, deltaTime)
|
||||
|
||||
controller.applyGlobalPitch(state.currPitchCorrectionForce.get().toRadians())
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, state.currPitchCorrectionForce.get(), state.currRollCorrectionForce.get())
|
||||
return Vec3(0.0, 0.0, state.currRollCorrectionForce.get())
|
||||
}
|
||||
|
||||
private fun correctOrientation(
|
||||
@@ -299,10 +314,10 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
// Calculate correcting roll force.
|
||||
// Mult by cos(pitch) to ensure that it doesn't roll correct at when diving or climbing
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect)
|
||||
val maxRollCorrectionRate = if (state.rideVelocity.get().length() < 0.1) 15.0f else 8.0f * (cos(controller.pitch.toRadians())).pow(2) * ((state.noInputTime.get() - rollCorrectionTimer) * 2).coerceIn(0.0, 1.0).toFloat()
|
||||
val maxRollCorrectionRate = if (state.rideVelocity.get().length() < 0.1) 15.0f else 8.0f * (cos(controller.pitch.toRadians())).pow(2) * ((state.noInputTimeRoll.get() - rollCorrectionTimer)).coerceIn(0.0, 1.0).toFloat()
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0
|
||||
val rollArrivalDeg = 90.0
|
||||
if(state.rideVelocity.get().length() < 0.1 || state.noInputTime.get() > rollCorrectionTimer) {
|
||||
if(state.rideVelocity.get().length() < 0.1 || state.noInputTimeRoll.get() > rollCorrectionTimer) {
|
||||
val arrivalInfluence = (min(rollArrivalDeg,abs(controller.roll).toDouble()) / rollArrivalDeg)
|
||||
val desiredRollForce = (0 - controller.roll).sign * maxRollCorrectionRate * arrivalInfluence
|
||||
var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
@@ -324,13 +339,18 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
}
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
val maxPitchCorrectionRate = 15
|
||||
val maxPitchForce = maxPitchCorrectionRate / 40.0
|
||||
val pitchArrivalDeg = 90.0
|
||||
if(state.rideVelocity.get().length() < 0.1) {
|
||||
val arrivalInfluence = (min(pitchArrivalDeg,abs(controller.pitch).toDouble()) / pitchArrivalDeg)
|
||||
val desiredPitchForce = (0 - controller.pitch).sign * maxPitchCorrectionRate * arrivalInfluence
|
||||
var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
|
||||
val maxPitchCorrectionRate = if (state.currUpsideDownForce.get() != 0.0) 8f * state.currUpsideDownForce.get() else 15f
|
||||
val maxPitchForce = maxPitchCorrectionRate.toFloat() / 40.0f
|
||||
val pitchArrivalDeg = 45.0f
|
||||
var desiredPitch = if (state.currUpsideDownForce.get() != 0.0) 90.0 else 0.0
|
||||
// if (cos(controller.roll.toRadians()) < 0.0) {
|
||||
// desiredPitch *= -1 // If not rolled over then flip the pitch force. There are better ways to do this :(
|
||||
// }
|
||||
|
||||
if((state.rideVelocity.get().length() < 0.1 && controller.pitch < 0.0) || state.currUpsideDownForce.get() != 0.0) {
|
||||
val arrivalInfluence = (min(pitchArrivalDeg,abs(Mth.wrapDegrees(desiredPitch.toFloat().angleDifference(controller.pitch)))) / pitchArrivalDeg)
|
||||
val desiredPitchForce = maxPitchCorrectionRate.toFloat() * arrivalInfluence
|
||||
var steeredPitchForce = (desiredPitchForce - state.currPitchCorrectionForce.get())
|
||||
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredPitchForce) > maxPitchForce) {
|
||||
@@ -361,12 +381,23 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
// Begin the roll correction time counter if not enough mouse input
|
||||
// is detected
|
||||
if (abs(mouseX) < 1 && abs(mouseY) < 1) {
|
||||
state.noInputTime.set(state.noInputTime.get() + deltaTime)
|
||||
if (mouseX < 1 && abs(mouseY) < 1) {
|
||||
state.noInputTimeRoll.set(state.noInputTimeRoll.get() + deltaTime)
|
||||
} else if (cos(controller.roll.toRadians()) < 0.1) {
|
||||
state.noInputTimeRoll.set(state.noInputTimeRoll.get() + deltaTime * 0.5)
|
||||
}
|
||||
else {
|
||||
state.noInputTimeRoll.set(0.0)
|
||||
}
|
||||
|
||||
if (abs(mouseY) < 1) {
|
||||
state.noInputTimePitch.set(state.noInputTimePitch.get() + deltaTime)
|
||||
} else {
|
||||
state.noInputTime.set(0.0)
|
||||
state.noInputTimePitch.set(0.0)
|
||||
}
|
||||
|
||||
return when {
|
||||
@@ -464,7 +495,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
val smoothingSpeed = 2.0
|
||||
val mouseXc = (mouseX).coerceIn(-45.0, 45.0) * mouseInputMult
|
||||
// When upside down apply a pitching force to nudge the player towards a dive. This reduces the 'weirdness'
|
||||
// of being upside down
|
||||
@@ -476,10 +507,10 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
val currHorzSpeed = state.rideVelocity.get().horizontalDistance()
|
||||
val hoverSpeed = 0.1
|
||||
|
||||
// Yaw locally when at or below hoverSpeed
|
||||
// Yaw locally when at or below hoverSpeed but not when pitched up or rolled over
|
||||
val yawDampen = abs(cos(controller.pitch.toRadians())).pow(2) * abs(cos(controller.roll.toRadians())).pow(2)
|
||||
val localYaw = if (currHorzSpeed < hoverSpeed) xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed))).coerceIn(0.0, 1.0)
|
||||
else xInput * 0.4 * cos(controller.roll.toRadians()).coerceIn(0.0f, 1.0f) * yawDampen
|
||||
else 0.0 //xInput * 0.4 * cos(controller.roll.toRadians()).coerceIn(0.0f, 1.0f) * yawDampen
|
||||
|
||||
// Pitch locally up or down depending upon a number of factors:
|
||||
// - Reduce pitch substantially when rolled and in a steep yaw. This prevents the player from ignoring a slow handling stat
|
||||
@@ -487,14 +518,17 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
// - pitch faster at higher speeds
|
||||
val p = 1.0 - vehicle.runtime.resolveDouble(settings.horizontalPitchExpr)
|
||||
var localPitch = yInput * (1 - abs(sin(controller.roll.toRadians())).pow(2) * p * hypot(controller.forwardVector.x.toDouble(), controller.forwardVector.z.toDouble()).toFloat())
|
||||
localPitch *= if (currHorzSpeed > hoverSpeed) RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed)
|
||||
localPitch *= if (currSpeed > hoverSpeed || yInput > 0.0) RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed).coerceIn(0.2, 1.0)
|
||||
else 0.0
|
||||
|
||||
// Roll less when slow and not at all when at hoverSpeed or lower.
|
||||
// Apply a roll righting force when trying to pitch hard while rolled sideways. This nudges the player towards
|
||||
// pitching globally
|
||||
val pitchInfluencedRollCorrection = 0.0
|
||||
val rollForce = if (currHorzSpeed > hoverSpeed) xInput * sqrt(abs(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed)).coerceIn(0.0,1.0)) + pitchInfluencedRollCorrection
|
||||
val howRolledAmI = (( cos(controller.roll.toRadians()) - 1).coerceIn(-1.0f, 0.0f) * -2).coerceIn(0.0f, 0.7f) //Coerce into how much roll you want to let in in the deadzone
|
||||
val inputInRolledDir = if (xInput.sign.toFloat() == controller.roll.sign) 1.0 else -cos(controller.roll.toRadians()).coerceIn(-1.0f, 0.0f).toDouble()
|
||||
val rollDampen = (1 - howRolledAmI * abs(cos(controller.pitch.toRadians())).pow(2) * inputInRolledDir)
|
||||
val rollForce = if (currHorzSpeed > hoverSpeed) xInput * sqrt(abs(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed)).coerceIn(0.0,1.0)) * rollDampen + pitchInfluencedRollCorrection
|
||||
else 0.0
|
||||
|
||||
//yaw, pitch, roll
|
||||
@@ -693,7 +727,8 @@ class BirdState : RidingBehaviourState() {
|
||||
var lastGlide = ridingState(-100L, Side.CLIENT)
|
||||
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
var currPitchCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
var noInputTime = ridingState(0.0, Side.CLIENT)
|
||||
var noInputTimeRoll = ridingState(0.0, Side.CLIENT)
|
||||
var noInputTimePitch = ridingState(0.0, Side.CLIENT)
|
||||
var currUpsideDownForce = ridingState(0.0, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
@@ -712,7 +747,8 @@ class BirdState : RidingBehaviourState() {
|
||||
lastGlide.set(-100L, forced = true)
|
||||
currRollCorrectionForce.set(0.0, forced = true)
|
||||
currPitchCorrectionForce.set(0.0, forced = true)
|
||||
noInputTime.set(0.0, forced = true)
|
||||
noInputTimeRoll.set(0.0, forced = true)
|
||||
noInputTimePitch.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
@@ -726,7 +762,8 @@ class BirdState : RidingBehaviourState() {
|
||||
it.lastGlide.set(this.lastGlide.get(), forced = true)
|
||||
it.currRollCorrectionForce.set(this.currRollCorrectionForce.get(), forced = true)
|
||||
it.currPitchCorrectionForce.set(this.currPitchCorrectionForce.get(), forced = true)
|
||||
it.noInputTime.set(this.noInputTime.get(), forced = true)
|
||||
it.noInputTimeRoll.set(this.noInputTimeRoll.get(), forced = true)
|
||||
it.noInputTimePitch.set(this.noInputTimePitch.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
@@ -735,3 +772,16 @@ class BirdState : RidingBehaviourState() {
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the shortest difference between two angles.
|
||||
* The result will be in the range [-180, 180].
|
||||
* A positive result indicates a clockwise direction from this angle to the other,
|
||||
* a negative result indicates a counter-clockwise direction.
|
||||
*/
|
||||
fun Float.angleDifference(other: Float): Float {
|
||||
var diff = other - this
|
||||
while (diff <= -180F) diff += 360F
|
||||
while (diff > 180F) diff -= 360F
|
||||
return diff
|
||||
}
|
||||
|
||||
-1
@@ -75,7 +75,6 @@ class GliderBehaviour : RidingBehaviour<GliderSettings, RidingBehaviourState> {
|
||||
val xVector = if (vehicle.runtime.resolveBoolean(settings.canStrafe)) driver.xxa.toDouble() else 0.0
|
||||
val yVector = -vehicle.runtime.resolveDouble(settings.glideSpeed)
|
||||
val zVector = driver.zza.toDouble()
|
||||
val speedStat = settings.calculate(RidingStat.SPEED, 0)
|
||||
return Vec3(xVector, yVector, zVector)
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -11,8 +11,6 @@ package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseState
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
@@ -27,7 +25,6 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.level.ClipContext
|
||||
@@ -131,8 +128,8 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr)).toFloat() / 20.0f
|
||||
|
||||
val newStam = if (state.tooHigh.get()) max(0.0f, stam - stamDrainRate) else min(1.0f,stam + stamDrainRate)
|
||||
val stamReplenishRate = (1.0f / vehicle.runtime.resolveDouble(settings.stamReplenishTimeSeconds) ).toFloat() / 20.0f // 2 seconds to replenish a full bar of stamina
|
||||
val newStam = if (state.tooHigh.get()) max(0.0f, stam - stamDrainRate) else min(1.0f,stam + stamReplenishRate)
|
||||
|
||||
state.stamina.set(newStam)
|
||||
}
|
||||
@@ -433,6 +430,9 @@ class HoverSettings : RidingBehaviourSettings {
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var stamReplenishTimeSeconds = "2.0".asExpression()
|
||||
private set
|
||||
|
||||
// Speed in block per second
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 7.0, 1.0)".asExpression()
|
||||
private set
|
||||
|
||||
+59
-27
@@ -26,6 +26,7 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
@@ -34,6 +35,7 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
@@ -87,7 +89,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
val boostKeyPressed = Minecraft.getInstance().options.keySprint.isDown()
|
||||
|
||||
if(state.stamina.get() != 0.0f && boostKeyPressed) {
|
||||
if (state.stamina.get() >= 0.25f) {
|
||||
if (state.stamina.get() >= 0.0f) {
|
||||
//If on the previous tick the boost key was held then don't change if the ride is boosting
|
||||
if(state.boostIsToggleable.get()) {
|
||||
//flip the boosting state if boost key is pressed
|
||||
@@ -115,11 +117,17 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
|
||||
if (state.boosting.get()) {
|
||||
newStam = max(0.0f,stam - stamDrainRate * 1.5f)
|
||||
|
||||
} else {
|
||||
newStam = max(0.0f,stam - stamDrainRate)
|
||||
}
|
||||
|
||||
// If out of stamina then increase noStamTickCnt
|
||||
if (newStam == 0.0f) {
|
||||
state.noStamTickCnt.set(state.noStamTickCnt.get() + 1)
|
||||
} else {
|
||||
state.noStamTickCnt.get()
|
||||
}
|
||||
|
||||
state.stamina.set(newStam)
|
||||
}
|
||||
|
||||
@@ -139,27 +147,26 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
var upForce = 0.0
|
||||
var forwardForce = 0.0
|
||||
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
if (controller == null || controller.orientation == null) return Vec3.ZERO
|
||||
|
||||
//Calculate ride space velocity
|
||||
calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
|
||||
//Translate ride space velocity to world space velocity.
|
||||
if (controller != null) {
|
||||
upForce = if(state.stamina.get() != 0.0f) -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
else min(0.0, -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z)
|
||||
forwardForce = cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
}
|
||||
|
||||
// The downward force used to encourage players to stop flying upside down.
|
||||
val extraDownwardForce = if(state.stamina.get() == 0.0f) -0.3 else 0.0 // 6 blocks a second downward
|
||||
val maxDownwardForceTickCnt = 20.0
|
||||
val extraDownwardForce = if(state.stamina.get() == 0.0f) -0.3 * (state.noStamTickCnt.get() / maxDownwardForceTickCnt).coerceIn(0.0, 1.0) else 0.0 // 6 blocks a second downward
|
||||
|
||||
val velocity = Vec3(0.0, upForce + extraDownwardForce, forwardForce)
|
||||
// Convert the local velocity vector into a world vector
|
||||
val localVelVec = Vector3f(
|
||||
state.rideVelocity.get().x.toFloat(),
|
||||
(state.rideVelocity.get().y).toFloat(),
|
||||
state.rideVelocity.get().z.toFloat() * -1.0f // Flip the z axis to make this left handed? orr.. right handed? idk, flip it though
|
||||
)
|
||||
var worldVelVec = localVelVec.mul(controller.orientation).toVec3d().yRot(vehicle.yRot.toRadians()) // Unrotate preemptively as this vector gets rotate later down the line in MC logic.
|
||||
worldVelVec = worldVelVec.add(0.0, extraDownwardForce, 0.0) // Add the stamina depletion force to bring the ride down.
|
||||
|
||||
return velocity
|
||||
return worldVelVec
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -172,9 +179,10 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
driver: Player
|
||||
) {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) / 20.0
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr) / 400.0
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed) / 20.0
|
||||
val speed = state.rideVelocity.get().length()
|
||||
val accel = topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr) * 20.0)
|
||||
val deccel = vehicle.runtime.resolveDouble(settings.deccelRate)//0.005
|
||||
val minSpeed = topSpeed * vehicle.runtime.resolveDouble(settings.minSpeedFactor)
|
||||
val speed = state.rideVelocity.get().z
|
||||
val boostMult = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
|
||||
val boostTopSpeed = topSpeed * boostMult
|
||||
@@ -187,7 +195,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
Vec3(
|
||||
state.rideVelocity.get().x,
|
||||
state.rideVelocity.get().y,
|
||||
max(state.rideVelocity.get().z - ((accel) / 2), minSpeed * 0.5)
|
||||
max(state.rideVelocity.get().z - (deccel * 1.3), 0.3 * 0.5)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -215,7 +223,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
Vec3(
|
||||
state.rideVelocity.get().x,
|
||||
state.rideVelocity.get().y,
|
||||
max(state.rideVelocity.get().z - ((accel) / 2), minSpeed)
|
||||
max(state.rideVelocity.get().z - (deccel), minSpeed)
|
||||
)
|
||||
)
|
||||
} else if (speed > topSpeed) {
|
||||
@@ -223,6 +231,17 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
state.rideVelocity.get().scale(0.98)
|
||||
)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Kill strafing velocities carried over from controller transition. Don't
|
||||
* kill immediately to give some momentum to transitions.
|
||||
***************************************************************************/
|
||||
state.rideVelocity.set(Vec3(
|
||||
lerp(state.rideVelocity.get().x, 0.0, 0.03),
|
||||
lerp(state.rideVelocity.get().y, 0.0, 0.03),
|
||||
state.rideVelocity.get().z
|
||||
))
|
||||
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
@@ -450,7 +469,12 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return if (state.boosting.get()) 1.2f else 1.0f
|
||||
val maxDownwardForceTickCnt = 20.0f
|
||||
return when {
|
||||
state.noStamTickCnt.get() != 0 -> 1f - 0.2f*(state.noStamTickCnt.get() / maxDownwardForceTickCnt).coerceIn(0.0f,1.0f)
|
||||
state.boosting.get() -> 1.2f
|
||||
else -> 1.0f
|
||||
}
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
|
||||
@@ -526,7 +550,11 @@ class JetSettings : RidingBehaviourSettings {
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
|
||||
var minSpeed: Expression = "12.0".asExpression()
|
||||
var deccelRate: Expression = "0.005".asExpression()
|
||||
private set
|
||||
|
||||
// Mult to top speed in order to derive minSpeed
|
||||
var minSpeedFactor: Expression = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 50.0, 25.0)".asExpression()
|
||||
@@ -541,14 +569,14 @@ class JetSettings : RidingBehaviourSettings {
|
||||
private set
|
||||
|
||||
// Turn rate in degrees per second
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 60.0, 20.0)".asExpression()
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 60.0, 10.0)".asExpression()
|
||||
private set
|
||||
// Top Speed in blocks per second
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 24.0, 4.0)".asExpression()
|
||||
private set
|
||||
// Acceleration in blocks per s^2
|
||||
// Seconds to get to top speed
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', 4.0, 1.0)".asExpression()
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', 2.0, 8.0)".asExpression()
|
||||
private set
|
||||
// Time in seconds to drain full bar of stamina flying
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 60.0, 4.0)".asExpression()
|
||||
@@ -561,7 +589,8 @@ class JetSettings : RidingBehaviourSettings {
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(minSpeed)
|
||||
buffer.writeExpression(deccelRate)
|
||||
buffer.writeExpression(minSpeedFactor)
|
||||
buffer.writeExpression(handlingYawExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
@@ -575,7 +604,8 @@ class JetSettings : RidingBehaviourSettings {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
gravity = buffer.readExpression()
|
||||
minSpeed = buffer.readExpression()
|
||||
deccelRate = buffer.readExpression()
|
||||
minSpeedFactor = buffer.readExpression()
|
||||
handlingYawExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
@@ -593,6 +623,7 @@ class JetState : RidingBehaviourState() {
|
||||
var boosting = ridingState(false, Side.BOTH)
|
||||
var boostIsToggleable = ridingState(false, Side.BOTH)
|
||||
var canSpeedBurst = ridingState(false, Side.BOTH)
|
||||
var noStamTickCnt = ridingState(0, Side.CLIENT) // Value that is increased for every tick you are out of stamina
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
@@ -619,6 +650,7 @@ class JetState : RidingBehaviourState() {
|
||||
boosting.set(false, forced = true)
|
||||
boostIsToggleable.set(false, forced = true)
|
||||
canSpeedBurst.set(true, forced = true)
|
||||
noStamTickCnt.set(0, forced = true)
|
||||
}
|
||||
|
||||
override fun copy() = JetState().also {
|
||||
|
||||
+20
-5
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -30,6 +31,7 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Matrix3f
|
||||
import kotlin.math.*
|
||||
|
||||
class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
@@ -243,8 +245,21 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
* Gather the previous velocity and check for horizontal
|
||||
* collisions
|
||||
*****************************************************/
|
||||
val dmSpeed = vehicle.deltaMovement.length()
|
||||
val rvSpeed = state.rideVelocity.get().length()
|
||||
var newVelocity = state.rideVelocity.get() //.normalize().scale(vehicle.deltaMovement.horizontalDistance())
|
||||
|
||||
/******************************************************
|
||||
* Gather the previous velocity and check for horizontal
|
||||
* collisions
|
||||
*****************************************************/
|
||||
// if (dmSpeed > rvSpeed) {
|
||||
// // align the velocity vector to be in local vehicle space
|
||||
// newVelocity = vehicle.deltaMovement
|
||||
// val yawAligned = Matrix3f().rotateY(-vehicle.yRot.toRadians())
|
||||
// newVelocity = (newVelocity.toVector3f().mul(yawAligned)).toVec3d()
|
||||
// }
|
||||
|
||||
if (vehicle.horizontalCollision) {
|
||||
newVelocity = newVelocity.normalize().scale(vehicle.deltaMovement.length())
|
||||
}
|
||||
@@ -507,23 +522,23 @@ class HorseSettings : RidingBehaviourSettings {
|
||||
var lookYawLimit = "90.0f".asExpression()
|
||||
private set
|
||||
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.0, 0.4)".asExpression()
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.2, 0.1)".asExpression()
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', 0.5, 2.0)".asExpression()
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', 0.1, 12.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'LAND', 30.0, 10.0)".asExpression()
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'LAND', 60.0, 4.0)".asExpression()
|
||||
private set
|
||||
|
||||
//Between a one block jump and a six block jump
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 1.0, 0.38)".asExpression()
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 1.6, 0.2)".asExpression()
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LAND', 180.0, 40.0)".asExpression()
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LAND', 90.0, 30.0)".asExpression()
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
+19
-5
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
@@ -134,7 +135,7 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
|
||||
private fun applyVelocityFromInput(velocity: Vec3, vehicle: PokemonEntity, driver: Player, settings: BoatSettings, state: BoatState): Vec3 {
|
||||
val speed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val acceleration = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val acceleration = speed / (vehicle.runtime.resolveDouble(settings.accelerationExpr) * 20)
|
||||
|
||||
if (state.jumpBuffer.get() != -1 || !(vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
return velocity
|
||||
@@ -170,14 +171,25 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
|
||||
private fun applyGravity(velocity: Vec3, vehicle: PokemonEntity, settings: BoatSettings, state: BoatState): Vec3 {
|
||||
if (state.jumpBuffer.get() == -1 && (vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
val verticalVelocity = if (vehicle.isUnderWater) 0.5 else 0.0
|
||||
return Vec3(velocity.x, verticalVelocity, velocity.z)
|
||||
if (shouldFloatHigher(vehicle, settings)) {
|
||||
return Vec3(velocity.x, 0.5, velocity.z)
|
||||
}
|
||||
else {
|
||||
return Vec3(velocity.x, 0.0, velocity.z)
|
||||
}
|
||||
}
|
||||
val terminalVelocity = vehicle.runtime.resolveDouble(settings.terminalVelocity)
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2
|
||||
return Vec3(velocity.x, max(velocity.y - gravity, terminalVelocity), velocity.z)
|
||||
}
|
||||
|
||||
private fun shouldFloatHigher(vehicle: PokemonEntity, settings: BoatSettings): Boolean {
|
||||
val surfaceOffset = vehicle.runtime.resolveFloat(settings.surfaceLevelOffset)
|
||||
val blockPos = BlockPos.containing(vehicle.x, vehicle.eyeY + surfaceOffset, vehicle.z)
|
||||
val fluidState = vehicle.level().getFluidState(blockPos)
|
||||
return !fluidState.isEmpty
|
||||
}
|
||||
|
||||
private fun applyStrafeRotation(vehicle: PokemonEntity, driver: Player, settings: BoatSettings, state: BoatState) {
|
||||
val skillModifier = vehicle.runtime.resolveDouble(settings.rotationspeedModifierExpr)
|
||||
val strafe = driver.xxa
|
||||
@@ -394,14 +406,16 @@ class BoatSettings : RidingBehaviourSettings {
|
||||
var speedExpr = "q.get_ride_stats('SPEED', 'LIQUID', 2.0, 0.5)".asExpression()
|
||||
private set
|
||||
|
||||
var accelerationExpr = "q.get_ride_stats('ACCELERATION', 'LIQUID', 0.5, 0.05)".asExpression()
|
||||
var accelerationExpr = "q.get_ride_stats('ACCELERATION', 'LIQUID', 0.1, 12.0)".asExpression()
|
||||
private set
|
||||
|
||||
var sprintSpeedModifier = "1.5".asExpression()
|
||||
var sprintSpeedModifier = "q.get_ride_stats('JUMP', 'LIQUID', 1.5, 1.25)".asExpression()
|
||||
private set
|
||||
|
||||
var sprintFovModifier = "1.2".asExpression()
|
||||
|
||||
var surfaceLevelOffset = "0".asExpression()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeRidingStats(stats)
|
||||
|
||||
@@ -42,9 +42,10 @@ class RideLoopSound(val ride: PokemonEntity, val soundSettings: RideSoundSetting
|
||||
var fade: Float = 0.0f
|
||||
var shouldMuffle: Boolean = soundSettings.muffleEnabled
|
||||
var rideAttenuation: RideAttenuationModel = soundSettings.attenuationModel
|
||||
var muffleAmount: Float = 1.0f // Currently slightly misleading. 1.0 is on muffle and 0.0 is full hFgain muting
|
||||
// TODO: revisit below flag once multi passenger support is enabled
|
||||
var isPassenger: Boolean = Minecraft.getInstance().player?.id == ride.controllingPassenger?.id
|
||||
var muffleAmount: Float = 1.0f // Currently slightly misleading. 1.0 is no muffle and 0.0 is full hFgain muting
|
||||
var isPassenger: Boolean = ride.passengers.any { passenger ->
|
||||
Minecraft.getInstance().player?.id == passenger.id
|
||||
}
|
||||
|
||||
init {
|
||||
this.looping = true
|
||||
|
||||
@@ -21,11 +21,11 @@ import net.minecraft.network.chat.Component
|
||||
enum class RidingStat(
|
||||
val flavour: Flavour
|
||||
) {
|
||||
SPEED(Flavour.SWEET),
|
||||
ACCELERATION(Flavour.SPICY),
|
||||
SKILL(Flavour.DRY),
|
||||
JUMP(Flavour.BITTER),
|
||||
STAMINA(Flavour.SOUR);
|
||||
SPEED(Flavour.SWEET),
|
||||
STAMINA(Flavour.SOUR),
|
||||
JUMP(Flavour.BITTER);
|
||||
|
||||
companion object {
|
||||
fun getByName(name: String) = RidingStat.entries.firstOrNull { it.name.equals(name, ignoreCase = true) }
|
||||
|
||||
@@ -34,7 +34,7 @@ object CobblemonSpawnPools {
|
||||
SpawnablePositionTypePrecalculation,
|
||||
BucketPrecalculation,
|
||||
BiomePrecalculation
|
||||
)
|
||||
), reloadable = true
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ object CobblemonClient {
|
||||
teamData = ClientPlayerTeamData()
|
||||
clientPokedexData = ClientPokedexManager(mutableMapOf())
|
||||
storage.onLogin()
|
||||
CobblemonDataProvider.canReload = false
|
||||
// CobblemonDataProvider.canReload = false
|
||||
}
|
||||
|
||||
fun onLogout() {
|
||||
@@ -113,7 +113,7 @@ object CobblemonClient {
|
||||
battleOverlay.onLogout()
|
||||
ClientTaskTracker.clear()
|
||||
checkedStarterScreen = false
|
||||
CobblemonDataProvider.canReload = true
|
||||
// CobblemonDataProvider.canReload = true
|
||||
DeferredRenderer.clearAll()
|
||||
ClientPlayerIcon.clear()
|
||||
}
|
||||
|
||||
@@ -135,7 +135,11 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
|
||||
// Configure what controls to show for each behaviour
|
||||
when (currentBehaviourKey) {
|
||||
BirdBehaviour.KEY -> {}
|
||||
BoatBehaviour.KEY -> {}
|
||||
BoatBehaviour.KEY -> {
|
||||
showVerticalMouse = false
|
||||
showHorizontalMouse = false
|
||||
showSneakKey = false
|
||||
}
|
||||
BurstBehaviour.KEY -> {}
|
||||
DolphinBehaviour.KEY -> {}
|
||||
GliderBehaviour.KEY -> {}
|
||||
|
||||
@@ -82,9 +82,6 @@ class PokedexGUI private constructor(
|
||||
private val arrowUpIcon = cobblemonResource("textures/gui/pokedex/arrow_up.png")
|
||||
private val arrowDownIcon = cobblemonResource("textures/gui/pokedex/arrow_down.png")
|
||||
|
||||
private val tooltipEdge = cobblemonResource("textures/gui/pokedex/tooltip_edge.png")
|
||||
private val tooltipBackground = cobblemonResource("textures/gui/pokedex/tooltip_background.png")
|
||||
|
||||
private val tabSelectArrow = cobblemonResource("textures/gui/pokedex/select_arrow.png")
|
||||
private val tabIcons = arrayOf(
|
||||
cobblemonResource("textures/gui/pokedex/tab_info.png"),
|
||||
@@ -325,17 +322,15 @@ class PokedexGUI private constructor(
|
||||
|
||||
// Search type tooltip
|
||||
if (searchByTypeButton.isButtonHovered(mouseX, mouseY)) {
|
||||
matrices.pushPose()
|
||||
matrices.translate(0.0, 0.0, 1000.0)
|
||||
val searchTypeText = lang("ui.pokedex.search.search_by", lang("ui.pokedex.search.type.${selectedSearchByType.name.lowercase()}")).bold()
|
||||
val searchTypeTextWidth = Minecraft.getInstance().font.width(searchTypeText.font(CobblemonResources.DEFAULT_LARGE))
|
||||
val tooltipWidth = searchTypeTextWidth + 6
|
||||
|
||||
blitk(matrixStack = matrices, texture = tooltipEdge, x = mouseX - (tooltipWidth / 2) - 1, y = mouseY - 16, width = 1, height = 11)
|
||||
blitk(matrixStack = matrices, texture = tooltipBackground, x = mouseX - (tooltipWidth / 2), y = mouseY - 16, width = tooltipWidth, height = 11)
|
||||
blitk(matrixStack = matrices, texture = tooltipEdge, x = mouseX + (tooltipWidth / 2), y = mouseY - 16, width = 1, height = 11)
|
||||
drawScaledText(context = context, font = CobblemonResources.DEFAULT_LARGE, text = searchTypeText, x = mouseX, y = mouseY - 15, shadow = true, centered = true)
|
||||
matrices.popPose()
|
||||
renderTooltip(
|
||||
context,
|
||||
searchTypeText,
|
||||
mouseX,
|
||||
mouseY,
|
||||
delta,
|
||||
-14
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,6 +476,8 @@ class PokedexGUI private constructor(
|
||||
|
||||
fun displaytabInfoElement(tabIndex: Int, update: Boolean = true) {
|
||||
val showActiveTab = selectedEntry?.let { selectedForm in CobblemonClient.clientPokedexData.getCaughtForms(it) } == true
|
||||
var statSubIndex = 0
|
||||
|
||||
if (tabButtons.isNotEmpty() && tabButtons.size > tabIndex) {
|
||||
tabButtons.forEachIndexed { index, tab -> tab.isWidgetActive = showActiveTab && index == tabIndex
|
||||
}
|
||||
@@ -491,6 +488,14 @@ class PokedexGUI private constructor(
|
||||
removeWidget((tabInfoElement as AbilitiesWidget).rightButton)
|
||||
}
|
||||
|
||||
if (tabInfoIndex == TAB_STATS && tabInfoElement is StatsWidget) {
|
||||
statSubIndex = (tabInfoElement as StatsWidget).selectedStatTypeIndex
|
||||
removeWidget((tabInfoElement as StatsWidget).leftButton)
|
||||
removeWidget((tabInfoElement as StatsWidget).rightButton)
|
||||
removeWidget((tabInfoElement as StatsWidget).leftSubButton)
|
||||
removeWidget((tabInfoElement as StatsWidget).rightSubButton)
|
||||
}
|
||||
|
||||
tabInfoIndex = tabIndex
|
||||
if (::tabInfoElement.isInitialized) removeWidget(tabInfoElement)
|
||||
|
||||
@@ -508,7 +513,9 @@ class PokedexGUI private constructor(
|
||||
tabInfoElement = SizeWidget(x + 180, y + 135)
|
||||
}
|
||||
TAB_STATS -> {
|
||||
tabInfoElement = StatsWidget(x + 180, y + 135)
|
||||
tabInfoElement = StatsWidget(x + 180, y + 135).also {
|
||||
it.selectedStatTypeIndex = statSubIndex
|
||||
}
|
||||
}
|
||||
TAB_DROPS -> {
|
||||
tabInfoElement = DropsScrollingWidget(x + 189, y + 135)
|
||||
@@ -555,6 +562,17 @@ class PokedexGUI private constructor(
|
||||
}
|
||||
TAB_STATS -> {
|
||||
(tabInfoElement as StatsWidget).baseStats = form.baseStats
|
||||
(tabInfoElement as StatsWidget).rideProperties = form.riding
|
||||
|
||||
form.riding.behaviours?.let {
|
||||
addRenderableWidget((tabInfoElement as StatsWidget).leftButton)
|
||||
addRenderableWidget((tabInfoElement as StatsWidget).rightButton)
|
||||
|
||||
if (it.size > 1) {
|
||||
addRenderableWidget((tabInfoElement as StatsWidget).leftSubButton)
|
||||
addRenderableWidget((tabInfoElement as StatsWidget).rightSubButton)
|
||||
}
|
||||
}
|
||||
}
|
||||
TAB_DROPS -> {
|
||||
(tabInfoElement as DropsScrollingWidget).dropTable = form.drops
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.pokedex
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.font
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
|
||||
private val tooltipEdge = cobblemonResource("textures/gui/pokedex/tooltip_edge.png")
|
||||
private val tooltipBackground = cobblemonResource("textures/gui/pokedex/tooltip_background.png")
|
||||
|
||||
fun renderTooltip(context: GuiGraphics, text: MutableComponent, posX: Int, posY: Int, delta: Float, offsetY: Int = 0) {
|
||||
val poseStack = context.pose()
|
||||
val textWidth = Minecraft.getInstance().font.width(text.font(CobblemonResources.DEFAULT_LARGE))
|
||||
val tooltipWidth = textWidth + 6
|
||||
val tooltipHeight = 11
|
||||
val tooltipTop = posY + offsetY
|
||||
|
||||
poseStack.pushPose()
|
||||
poseStack.translate(0.0, 0.0, 1000.0)
|
||||
Minecraft.getInstance().let {
|
||||
it.mainRenderTarget.bindWrite(false)
|
||||
context.enableScissor(
|
||||
posX - (tooltipWidth / 2),
|
||||
tooltipTop + 1,
|
||||
(posX - (tooltipWidth / 2)) + tooltipWidth,
|
||||
tooltipTop + 10
|
||||
)
|
||||
it.gameRenderer.processBlurEffect(delta)
|
||||
context.disableScissor()
|
||||
it.mainRenderTarget.bindWrite(true)
|
||||
}
|
||||
|
||||
blitk(matrixStack = poseStack, texture = tooltipEdge, x = posX - (tooltipWidth / 2) - 1, y = tooltipTop, width = 1, height = tooltipHeight)
|
||||
blitk(matrixStack = poseStack, texture = tooltipBackground, x = posX - (tooltipWidth / 2), y = tooltipTop, width = tooltipWidth, height = tooltipHeight)
|
||||
blitk(matrixStack = poseStack, texture = tooltipEdge, x = posX + (tooltipWidth / 2), y = tooltipTop, width = 1, height = tooltipHeight)
|
||||
drawScaledText(context = context, font = CobblemonResources.DEFAULT_LARGE, text = text, x = posX, y = tooltipTop + 1, shadow = true, centered = true)
|
||||
poseStack.popPose()
|
||||
}
|
||||
@@ -31,6 +31,7 @@ class ScaledButton(
|
||||
): Button(buttonX.toInt(), buttonY.toInt(), buttonWidth.toInt(), buttonHeight.toInt(), "".text(), clickAction, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
|
||||
var isWidgetActive = false
|
||||
var isVisible = true
|
||||
|
||||
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double) = false
|
||||
override fun defaultButtonNarrationText(builder: NarrationElementOutput) {
|
||||
@@ -38,8 +39,7 @@ class ScaledButton(
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
val matrices = context.pose()
|
||||
|
||||
if (resource != null) {
|
||||
if (isVisible && resource != null) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = resource,
|
||||
@@ -55,14 +55,14 @@ class ScaledButton(
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (active && isButtonHovered(mouseX, mouseY)) {
|
||||
if (isVisible && active && isButtonHovered(mouseX, mouseY)) {
|
||||
super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
if (active && !this.silent) {
|
||||
if (isVisible && active && !this.silent) {
|
||||
soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.POKEDEX_CLICK_SHORT, 1.0F))
|
||||
}
|
||||
}
|
||||
@@ -71,4 +71,4 @@ class ScaledButton(
|
||||
return mouseX.toFloat() in (buttonX..(buttonX + (buttonWidth.toFloat() * scale)))
|
||||
&& mouseY.toFloat() in (buttonY..(buttonY + (buttonHeight.toFloat() * scale)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -48,12 +48,11 @@ class AbilitiesWidget(x: Int, y: Int): InfoTextScrollWidget(pX = x, pY = y) {
|
||||
init { setAbility() }
|
||||
|
||||
private fun switchAbility(nextIndex: Boolean) {
|
||||
if (nextIndex) {
|
||||
if (selectedAbilitiesIndex < abilitiesList.lastIndex) selectedAbilitiesIndex++
|
||||
else selectedAbilitiesIndex = 0
|
||||
val size = abilitiesList.size
|
||||
selectedAbilitiesIndex = if (nextIndex) {
|
||||
(selectedAbilitiesIndex + 1) % size
|
||||
} else {
|
||||
if (selectedAbilitiesIndex > 0) selectedAbilitiesIndex--
|
||||
else selectedAbilitiesIndex = abilitiesList.lastIndex
|
||||
(selectedAbilitiesIndex - 1 + size) % size
|
||||
}
|
||||
setAbility()
|
||||
}
|
||||
|
||||
+10
-10
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.gui.pokedex.widgets
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.gui.ParentWidget
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
@@ -33,6 +34,7 @@ import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.PORTRAIT_
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.PORTRAIT_POKE_BALL_WIDTH
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.ScaledButton
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.renderTooltip
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
|
||||
@@ -94,9 +96,6 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
private val buttonGenderFemale = cobblemonResource("textures/gui/pokedex/button_female.png")
|
||||
private val buttonNone = cobblemonResource("textures/gui/pokedex/button_none.png")
|
||||
private val buttonShiny = cobblemonResource("textures/gui/pokedex/button_shiny.png")
|
||||
|
||||
private val tooltipEdge = cobblemonResource("textures/gui/pokedex/tooltip_edge.png")
|
||||
private val tooltipBackground = cobblemonResource("textures/gui/pokedex/tooltip_background.png")
|
||||
}
|
||||
|
||||
var currentEntry : PokedexEntry? = null
|
||||
@@ -440,13 +439,14 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
// Tooltip
|
||||
if (it.isVisible() && it.getWidget().isButtonHovered(mouseX, mouseY)) {
|
||||
val variationText = it.variation.displayName.asTranslated().bold()
|
||||
val variationTextWidth = Minecraft.getInstance().font.width(variationText.font(CobblemonResources.DEFAULT_LARGE))
|
||||
val tooltipWidth = variationTextWidth + 6
|
||||
|
||||
blitk(matrixStack = matrices, texture = tooltipEdge, x = mouseX - (tooltipWidth / 2) - 1, y = mouseY + 8, width = 1, height = 11)
|
||||
blitk(matrixStack = matrices, texture = tooltipBackground, x = mouseX - (tooltipWidth / 2), y = mouseY + 8, width = tooltipWidth, height = 11)
|
||||
blitk(matrixStack = matrices, texture = tooltipEdge, x = mouseX + (tooltipWidth / 2), y = mouseY + 8, width = 1, height = 11)
|
||||
drawScaledText(context = context, font = CobblemonResources.DEFAULT_LARGE, text = variationText, x = mouseX, y = mouseY + 9, shadow = true, centered = true)
|
||||
renderTooltip(
|
||||
context,
|
||||
variationText,
|
||||
mouseX,
|
||||
mouseY,
|
||||
delta,
|
||||
10
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+218
-17
@@ -11,18 +11,24 @@ package com.cobblemon.mod.common.client.gui.pokedex.widgets
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.RidingProperties
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.HALF_OVERLAY_WIDTH
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.POKEMON_DESCRIPTION_HEIGHT
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.PokedexGUIConstants.SCALE
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.ScaledButton
|
||||
import com.cobblemon.mod.common.client.gui.pokedex.renderTooltip
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.util.FastColor
|
||||
|
||||
class StatsWidget(val pX: Int, val pY: Int) : SoundlessWidget(
|
||||
pX,
|
||||
@@ -33,6 +39,18 @@ class StatsWidget(val pX: Int, val pY: Int) : SoundlessWidget(
|
||||
) {
|
||||
|
||||
companion object {
|
||||
const val STAT_TYPE_BASE = 0
|
||||
const val STAT_TYPE_RIDE = 1
|
||||
const val MAX_BAR_WIDTH = 75
|
||||
|
||||
private val statTypes = listOf(STAT_TYPE_BASE, STAT_TYPE_RIDE)
|
||||
|
||||
private val divider = cobblemonResource("textures/gui/pokedex/info_stat_divider.png")
|
||||
private val arrowLeft = cobblemonResource("textures/gui/pokedex/info_arrow_left.png")
|
||||
private val arrowRight = cobblemonResource("textures/gui/pokedex/info_arrow_right.png")
|
||||
private val subArrowLeft = cobblemonResource("textures/gui/pokedex/info_sub_arrow_left.png")
|
||||
private val subArrowRight = cobblemonResource("textures/gui/pokedex/info_sub_arrow_right.png")
|
||||
|
||||
private val statLabels = arrayOf(
|
||||
lang("ui.stats.hp"),
|
||||
lang("ui.stats.atk"),
|
||||
@@ -52,12 +70,91 @@ class StatsWidget(val pX: Int, val pY: Int) : SoundlessWidget(
|
||||
)
|
||||
}
|
||||
|
||||
val leftButton: ScaledButton = ScaledButton(
|
||||
pX + 2.5F,
|
||||
pY - 8F,
|
||||
7,
|
||||
10,
|
||||
arrowLeft,
|
||||
clickAction = { switchStatType(false) }
|
||||
)
|
||||
|
||||
val rightButton: ScaledButton = ScaledButton(
|
||||
pX + 133F,
|
||||
pY - 8F,
|
||||
7,
|
||||
10,
|
||||
arrowRight,
|
||||
clickAction = { switchStatType(true) }
|
||||
)
|
||||
|
||||
val leftSubButton: ScaledButton = ScaledButton(
|
||||
pX + 2.5F,
|
||||
pY + 18.5F,
|
||||
7,
|
||||
10,
|
||||
subArrowLeft,
|
||||
clickAction = { switchRideBehaviour(false) }
|
||||
)
|
||||
|
||||
val rightSubButton: ScaledButton = ScaledButton(
|
||||
pX + 133F,
|
||||
pY + 18.5F,
|
||||
7,
|
||||
10,
|
||||
subArrowRight,
|
||||
clickAction = { switchRideBehaviour(true) }
|
||||
)
|
||||
|
||||
var selectedRideBehavioursIndex: Int = 0
|
||||
|
||||
var selectedStatTypeIndex: Int = STAT_TYPE_BASE
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
val isRideStatVisible = value == STAT_TYPE_RIDE
|
||||
leftSubButton.visible = isRideStatVisible
|
||||
rightSubButton.visible = isRideStatVisible
|
||||
}
|
||||
|
||||
var baseStats: Map<Stat, Int>? = null
|
||||
var rideProperties: RidingProperties? = null
|
||||
|
||||
private fun switchStatType(nextIndex: Boolean) {
|
||||
val size = statTypes.size
|
||||
selectedStatTypeIndex = if (nextIndex) {
|
||||
(selectedStatTypeIndex + 1) % size
|
||||
} else {
|
||||
(selectedStatTypeIndex - 1 + size) % size
|
||||
}
|
||||
|
||||
val showSubArrowButtons = selectedStatTypeIndex == STAT_TYPE_RIDE
|
||||
leftSubButton.visible = showSubArrowButtons
|
||||
rightSubButton.visible = showSubArrowButtons
|
||||
}
|
||||
|
||||
private fun switchRideBehaviour(nextIndex: Boolean) {
|
||||
val size = rideProperties?.behaviours?.size ?: 0
|
||||
selectedRideBehavioursIndex = if (nextIndex) {
|
||||
(selectedRideBehavioursIndex + 1) % size
|
||||
} else {
|
||||
(selectedRideBehavioursIndex - 1 + size) % size
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
if (baseStats == null) return
|
||||
when (selectedStatTypeIndex) {
|
||||
STAT_TYPE_BASE -> {
|
||||
renderBaseStats(context)
|
||||
}
|
||||
STAT_TYPE_RIDE -> {
|
||||
renderRideStats(context, mouseX, mouseY, delta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val matrices = context.pose()
|
||||
private fun renderBaseStats(context: GuiGraphics) {
|
||||
if (baseStats == null) return
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
@@ -68,18 +165,9 @@ class StatsWidget(val pX: Int, val pY: Int) : SoundlessWidget(
|
||||
shadow = true
|
||||
)
|
||||
|
||||
// Divider
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = pX + 50.5,
|
||||
y = pY + 4,
|
||||
height = 33.5,
|
||||
width = 1,
|
||||
red = 0.71F,
|
||||
green = 0.95F,
|
||||
blue = 0.95F
|
||||
)
|
||||
val matrices = context.pose()
|
||||
|
||||
blitk(matrixStack = matrices, texture = divider, x = pX + 51, y = pY + 4, height = 33.5, width = 1)
|
||||
|
||||
for (i in statLabels.indices) {
|
||||
drawScaledText(
|
||||
@@ -107,10 +195,10 @@ class StatsWidget(val pX: Int, val pY: Int) : SoundlessWidget(
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = pX + 54.5,
|
||||
x = pX + 55,
|
||||
y = pY + 4 + (6 * i),
|
||||
height = 3.5F,
|
||||
width = (statValue / 255F) * 77,
|
||||
width = (statValue / 255F) * MAX_BAR_WIDTH,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue
|
||||
@@ -119,6 +207,119 @@ class StatsWidget(val pX: Int, val pY: Int) : SoundlessWidget(
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderRideStats(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
rideProperties?.behaviours?.let { behaviours ->
|
||||
val selectedBehaviour = behaviours.entries.toList()[selectedRideBehavioursIndex]
|
||||
val behaviourStats = selectedBehaviour.value.stats
|
||||
|
||||
val matrices = context.pose()
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = Component.translatable("cobblemon.ui.pokedex.info.stats_ride").bold(),
|
||||
x = pX + 9,
|
||||
y = pY - 10,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
rideProperties?.seats?.size?.let { seats ->
|
||||
drawScaledTextJustifiedRight(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = Component.translatable("cobblemon.ui.pokedex.info.stats_ride.seats", seats).bold(),
|
||||
x = pX + 130,
|
||||
y = pY - 10,
|
||||
shadow = true
|
||||
)
|
||||
}
|
||||
|
||||
blitk(matrixStack = matrices, texture = divider, x = pX + 51, y = pY + 10, height = 27.5, width = 1)
|
||||
blitk(matrixStack = matrices, texture = divider, x = pX + 9, y = pY + 2, height = 6, width = 121)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.ride_style.${selectedBehaviour.key.name.lowercase()}").bold(),
|
||||
x = pX + 69.5,
|
||||
y = pY + 3,
|
||||
colour = 0x3A96B6,
|
||||
scale = SCALE,
|
||||
centered = true
|
||||
)
|
||||
|
||||
RidingStat.entries.forEachIndexed { index, stat ->
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.stats.ride.${stat.name.lowercase()}").bold(),
|
||||
x = pX + 9,
|
||||
y = pY + 10 + (6 * index),
|
||||
colour = 0x606B6E,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
behaviourStats[stat]?.let { range ->
|
||||
val startPosY = pY + 10 + (6F * index)
|
||||
|
||||
val red = FastColor.ARGB32.red(stat.flavour.colour) / 255F
|
||||
val green = FastColor.ARGB32.green(stat.flavour.colour) / 255F
|
||||
val blue = FastColor.ARGB32.blue(stat.flavour.colour) / 255F
|
||||
|
||||
val barStart = pX + 55F
|
||||
val baseStatWidth = (range.start / 100F) * MAX_BAR_WIDTH
|
||||
val boostedStatWidth = ((range.endInclusive / 100F) * MAX_BAR_WIDTH) - baseStatWidth
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = barStart,
|
||||
y = startPosY,
|
||||
height = 3.5F,
|
||||
width = baseStatWidth,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue
|
||||
)
|
||||
|
||||
val isBoostedStatHovered = mouseX.toFloat() in ((barStart + baseStatWidth)..(barStart + baseStatWidth + boostedStatWidth)) && mouseY.toFloat() in (startPosY..(startPosY + 3.5F))
|
||||
|
||||
drawScaledTextJustifiedRight(
|
||||
context = context,
|
||||
text = if (isBoostedStatHovered) range.endInclusive.toString().text().bold() else range.start.toString().text(),
|
||||
x = pX + 48,
|
||||
y = startPosY,
|
||||
colour = 0x3A96B6,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
// Boostable range
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = barStart + baseStatWidth,
|
||||
y = startPosY,
|
||||
height = 3.5F,
|
||||
width = boostedStatWidth,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue,
|
||||
alpha = if (isBoostedStatHovered) 1F else 0.5F
|
||||
)
|
||||
|
||||
if (isBoostedStatHovered) renderTooltip(
|
||||
context,
|
||||
lang("ui.stats.ride.boost_maximum").bold(),
|
||||
mouseX,
|
||||
mouseY,
|
||||
delta,
|
||||
-16
|
||||
)
|
||||
}
|
||||
}
|
||||
} ?: run {
|
||||
// If ride properties null, reset index to base stats
|
||||
selectedStatTypeIndex = STAT_TYPE_BASE
|
||||
}
|
||||
}
|
||||
|
||||
private fun getStatValueRGB(value: Int): Triple<Float, Float, Float> {
|
||||
when {
|
||||
value >= 150 -> return Triple(0.647F, 0.929F, 0.647F)
|
||||
@@ -128,4 +329,4 @@ class StatsWidget(val pX: Int, val pY: Int) : SoundlessWidget(
|
||||
}
|
||||
return Triple(0.964F, 0.64F, 0.502F)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class SummaryButton(
|
||||
override fun defaultButtonNarrationText(builder: NarrationElementOutput) {
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
public override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
if (!this.renderRequirement.invoke(this)) {
|
||||
return
|
||||
}
|
||||
|
||||
+47
-39
@@ -28,83 +28,91 @@ import net.minecraft.world.phys.Vec3
|
||||
* @author Hiroku
|
||||
* @since November 13th, 2023
|
||||
*/
|
||||
class BarSummarySpeciesFeatureRenderer(
|
||||
open class BarSummarySpeciesFeatureRenderer(
|
||||
override val name: String,
|
||||
val displayName: MutableComponent,
|
||||
val min: Int,
|
||||
val max: Int,
|
||||
val colour: Vec3,
|
||||
val underlay: ResourceLocation,
|
||||
val overlay: ResourceLocation,
|
||||
val pokemon: Pokemon
|
||||
val pokemon: Pokemon,
|
||||
val min: Int,
|
||||
val max: Int,
|
||||
val value: Int = 0,
|
||||
val colour: Vec3? = null
|
||||
) : SummarySpeciesFeatureRenderer<IntSpeciesFeature> {
|
||||
override fun render(GuiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon, feature: IntSpeciesFeature) {
|
||||
val value = feature.value
|
||||
val barRatio = (value - min) / (max - min).toFloat()
|
||||
val barWidth = Mth.ceil(barRatio * 108)
|
||||
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon, feature: IntSpeciesFeature) {
|
||||
renderElement(guiGraphics, x, y, pokemon, feature.value)
|
||||
}
|
||||
|
||||
open fun renderElement(guiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon, barValue: Int = value) {
|
||||
val barRatio = (barValue - min) / (max - min).toFloat()
|
||||
val barWidth = Mth.ceil(barRatio * 110)
|
||||
|
||||
blitk(
|
||||
matrixStack = GuiGraphics.pose(),
|
||||
matrixStack = guiGraphics.pose(),
|
||||
texture = underlay,
|
||||
x = x,
|
||||
y = y,
|
||||
height = 28,
|
||||
width = 124
|
||||
height = 24,
|
||||
width = 116
|
||||
)
|
||||
|
||||
val red = colour.x / 255F
|
||||
val green = colour.y / 255F
|
||||
val blue = colour.z / 255F
|
||||
renderBar(guiGraphics, x, y, barValue, barRatio, barWidth)
|
||||
|
||||
blitk(
|
||||
matrixStack = GuiGraphics.pose(),
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = x + 8,
|
||||
y = y + 16,
|
||||
height = 10,
|
||||
width = barWidth,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue
|
||||
)
|
||||
|
||||
blitk(
|
||||
matrixStack = GuiGraphics.pose(),
|
||||
matrixStack = guiGraphics.pose(),
|
||||
texture = overlay,
|
||||
x = x / StatWidget.SCALE,
|
||||
y = (y + 16) / StatWidget.SCALE,
|
||||
x = (x + 3) / StatWidget.SCALE,
|
||||
y = (y + 13) / StatWidget.SCALE,
|
||||
height = 20,
|
||||
width = 248,
|
||||
width = 220,
|
||||
scale = StatWidget.SCALE
|
||||
)
|
||||
|
||||
// Label
|
||||
drawScaledText(
|
||||
context = GuiGraphics,
|
||||
context = guiGraphics,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = displayName.bold(),
|
||||
x = x + 62,
|
||||
x = x + 58,
|
||||
y = y + 2.5,
|
||||
centered = true,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = GuiGraphics,
|
||||
text = value.toString().text(),
|
||||
x = x + 11,
|
||||
context = guiGraphics,
|
||||
text = barValue.toString().text(),
|
||||
x = x + 9,
|
||||
y = y + 6,
|
||||
scale = StatWidget.SCALE,
|
||||
centered = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = GuiGraphics,
|
||||
context = guiGraphics,
|
||||
text = "${Mth.floor(barRatio * 100)}%".text(),
|
||||
x = x + 113,
|
||||
x = x + 107,
|
||||
y = y + 6,
|
||||
scale = StatWidget.SCALE,
|
||||
centered = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
open fun renderBar(guiGraphics: GuiGraphics, x: Float, y: Float, barValue: Int, barRatio: Float, barWidth: Int) {
|
||||
val red = (colour?.x ?: 255.0) / 255.0
|
||||
val green = (colour?.y ?: 255.0) / 255.0
|
||||
val blue = (colour?.z ?: 255.0) / 255.0
|
||||
|
||||
blitk(
|
||||
matrixStack = guiGraphics.pose(),
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = x + 3,
|
||||
y = y + 13,
|
||||
height = 10,
|
||||
width = barWidth,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -23,10 +23,10 @@ interface SummarySpeciesFeatureRenderer<T : SynchronizedSpeciesFeature> {
|
||||
/** The name of the feature (so we know where to look to find it in the [Pokemon]) */
|
||||
val name: String
|
||||
/** Draws it at a particular position. */
|
||||
fun render(GuiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon, feature: T)
|
||||
fun render(GuiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon): Boolean {
|
||||
fun render(guiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon, feature: T)
|
||||
fun render(guiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon): Boolean {
|
||||
val feature = pokemon.getFeature<T>(name) ?: return false
|
||||
render(GuiGraphics, x, y, pokemon, feature)
|
||||
render(guiGraphics, x, y, pokemon, feature)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+403
-448
@@ -14,12 +14,16 @@ import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SynchronizedSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.italicise
|
||||
import com.cobblemon.mod.common.api.text.onHover
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.summary.SummaryButton
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.BarSummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.features.FriendshipFeatureRenderer
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.features.FullnessFeatureRenderer
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -39,8 +43,6 @@ import net.minecraft.util.Mth.ceil
|
||||
import net.minecraft.util.Mth.floor
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class StatWidget(
|
||||
pX: Int, pY: Int,
|
||||
@@ -51,63 +53,129 @@ class StatWidget(
|
||||
companion object {
|
||||
// Stat tab options
|
||||
private const val STATS = "stats"
|
||||
private const val IV = "iv"
|
||||
private const val EV = "ev"
|
||||
private const val IV = "ivs"
|
||||
private const val EV = "evs"
|
||||
private const val RIDE = "ride"
|
||||
private const val OTHER = "other"
|
||||
|
||||
private val statOptions = listOf(STATS, IV, EV, OTHER)
|
||||
|
||||
private const val statTabWidth = 24
|
||||
private const val OTHER_STAT_BARS_PER_PAGE = 4
|
||||
private const val STAT_TAB_WIDTH_6 = 22
|
||||
private const val STAT_TAB_WIDTH_5 = 24
|
||||
private const val MARKER_WIDTH = 8
|
||||
private const val WIDTH = 134
|
||||
private const val HEIGHT = 148
|
||||
const val SCALE = 0.5F
|
||||
|
||||
private const val WHITE = 0x00FFFFFF
|
||||
private const val GREY = 0x00AAAAAA
|
||||
private const val GREY = 0x008F8F8F
|
||||
private const val BLUE = 0x00548BFB
|
||||
private const val RED = 0x00FB5454
|
||||
|
||||
private val statsBaseResource = cobblemonResource("textures/gui/summary/summary_stats_chart_base.png")
|
||||
private val statsChartResource = cobblemonResource("textures/gui/summary/summary_stats_chart.png")
|
||||
private val statsChartPentagonResource = cobblemonResource("textures/gui/summary/summary_stats_chart_pentagon.png")
|
||||
private val statsOtherBaseResource = cobblemonResource("textures/gui/summary/summary_stats_other_base.png")
|
||||
private val statsOtherBarTemplate = cobblemonResource("textures/gui/summary/summary_stats_other_bar.png")
|
||||
private val friendshipOverlayResource = cobblemonResource("textures/gui/summary/summary_stats_friendship_overlay.png")
|
||||
private val fullnessOverlayResource = cobblemonResource("textures/gui/summary/summary_stats_fullness_overlay.png")
|
||||
private val statsOtherSidebarsResource = cobblemonResource("textures/gui/summary/summary_stats_other_sidebars.png")
|
||||
private val statsOtherSidebarArrowLeft = cobblemonResource("textures/gui/summary/summary_stats_other_sidebar_arrow_left.png")
|
||||
private val statsOtherSidebarArrowRight = cobblemonResource("textures/gui/summary/summary_stats_other_sidebar_arrow_right.png")
|
||||
private val tabMarkerResource = cobblemonResource("textures/gui/summary/summary_stats_tab_marker.png")
|
||||
private val statIncreaseResource = cobblemonResource("textures/gui/summary/summary_stats_icon_increase.png")
|
||||
private val statDecreaseResource = cobblemonResource("textures/gui/summary/summary_stats_icon_decrease.png")
|
||||
|
||||
private val statsLabel = lang("ui.stats")
|
||||
private val ivLabel = lang("ui.stats.ivs")
|
||||
private val evLabel = lang("ui.stats.evs")
|
||||
private val otherLabel = lang("ui.stats.other")
|
||||
private val statLabels: Map<MutableComponent, Stats> = mapOf(
|
||||
lang("ui.stats.hp").bold() to Stats.HP,
|
||||
lang("ui.stats.atk").bold() to Stats.ATTACK,
|
||||
lang("ui.stats.def").bold() to Stats.DEFENCE,
|
||||
lang("ui.stats.speed").bold() to Stats.SPEED,
|
||||
lang("ui.stats.sp_def").bold() to Stats.SPECIAL_DEFENCE,
|
||||
lang("ui.stats.sp_atk").bold() to Stats.SPECIAL_ATTACK
|
||||
)
|
||||
|
||||
private val hpLabel = lang("ui.stats.hp")
|
||||
private val spAtkLabel = lang("ui.stats.sp_atk")
|
||||
private val atkLabel = lang("ui.stats.atk")
|
||||
private val spDefLabel = lang("ui.stats.sp_def")
|
||||
private val defLabel = lang("ui.stats.def")
|
||||
private val speedLabel = lang("ui.stats.speed")
|
||||
private val hexagonVerticesOffset = listOf(
|
||||
Pair(67.0, 10.5), // 12 o'clock
|
||||
Pair(122.0, 42.5), // 2 o'clock
|
||||
Pair(122.0, 93.5), // 4 o'clock
|
||||
Pair(67.0, 124.5), // 6 o'clock
|
||||
Pair(12.0, 93.5), // 8 o'clock
|
||||
Pair(12.0, 42.5) // 10 o'clock
|
||||
)
|
||||
|
||||
private val pentagonVerticesOffset = listOf(
|
||||
Pair(67.0, 10.5), // 12 o'clock
|
||||
Pair(123.0, 47.5), // 2 o'clock
|
||||
Pair(103.0, 112.5), // 5 o'clock
|
||||
Pair(31.0, 112.5), // 7 o'clock
|
||||
Pair(11.0, 47.5), // 10 o'clock
|
||||
)
|
||||
}
|
||||
|
||||
var effectiveBattleIVs: Map<Stat, Int> = Stats.PERMANENT.associateWith { stat ->
|
||||
pokemon.ivs.getEffectiveBattleIV(stat)
|
||||
}
|
||||
private val statOptions = if (pokemon.form.riding.behaviours != null) listOf(STATS, IV, EV, RIDE, OTHER) else listOf(STATS, IV, EV, OTHER)
|
||||
|
||||
private var _statTabIndex: Int = tabIndex
|
||||
var statTabIndex: Int
|
||||
get() = _statTabIndex.coerceIn(0, statOptions.size - 1)
|
||||
set(value) {
|
||||
_statTabIndex = value.coerceIn(0, statOptions.size - 1)
|
||||
}
|
||||
|
||||
private var _rideBehaviourIndex: Int = 0
|
||||
var rideBehaviourIndex: Int
|
||||
get() = _rideBehaviourIndex.coerceIn(0, (pokemon.form.riding.behaviours?.size ?: 1) - 1)
|
||||
set(value) {
|
||||
_rideBehaviourIndex = value.coerceIn(0, (pokemon.form.riding.behaviours?.size ?: 1) - 1)
|
||||
}
|
||||
|
||||
val universalFeatures = listOf(
|
||||
FriendshipFeatureRenderer(pokemon),
|
||||
FullnessFeatureRenderer(pokemon)
|
||||
)
|
||||
|
||||
var statTabIndex = tabIndex
|
||||
val renderableFeatures = SpeciesFeatures
|
||||
.getFeaturesFor(pokemon.species)
|
||||
.filterIsInstance<SynchronizedSpeciesFeatureProvider<*>>()
|
||||
.mapNotNull { it.getRenderer(pokemon) }
|
||||
|
||||
private fun drawTriangle(
|
||||
colour: Vector3f,
|
||||
v1: Vec2,
|
||||
v2: Vec2,
|
||||
v3: Vec2
|
||||
) {
|
||||
var otherStatsPageIndex: Int = 0
|
||||
|
||||
var otherStatLeftButton: SummaryButton? = null
|
||||
var otherStatRightButton: SummaryButton? = null
|
||||
|
||||
init {
|
||||
if (renderableFeatures.size + universalFeatures.size > OTHER_STAT_BARS_PER_PAGE) {
|
||||
otherStatLeftButton = SummaryButton(
|
||||
x - 1F,
|
||||
y + 67F,
|
||||
14,
|
||||
14,
|
||||
resource = statsOtherSidebarArrowLeft,
|
||||
scale = SCALE,
|
||||
clickAction = { switchOtherStatsPage(false) }
|
||||
).also { addWidget(it) }
|
||||
|
||||
otherStatRightButton = SummaryButton(
|
||||
x + 128F,
|
||||
y + 67F,
|
||||
14,
|
||||
14,
|
||||
resource = statsOtherSidebarArrowRight,
|
||||
scale = SCALE,
|
||||
clickAction = { switchOtherStatsPage(true) }
|
||||
).also { addWidget(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun switchOtherStatsPage(nextIndex: Boolean) {
|
||||
val pages = ceil((renderableFeatures.size + universalFeatures.size).toDouble() / OTHER_STAT_BARS_PER_PAGE.toDouble())
|
||||
otherStatsPageIndex = if (nextIndex) {
|
||||
(otherStatsPageIndex + 1) % pages
|
||||
} else {
|
||||
(otherStatsPageIndex - 1 + pages) % pages
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawTriangle(colour: Vector3f, v1: Vec2, v2: Vec2, v3: Vec2, opacity: Float = 0.6F) {
|
||||
CobblemonResources.WHITE.let { RenderSystem.setShaderTexture(0, it) }
|
||||
RenderSystem.setShaderColor(colour.x, colour.y, colour.z, 0.6F)
|
||||
RenderSystem.setShaderColor(colour.x, colour.y, colour.z, opacity)
|
||||
val bufferBuilder = Tesselator.getInstance().begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION)
|
||||
bufferBuilder.addVertex(v1.x, v1.y, 10F)
|
||||
bufferBuilder.addVertex(v2.x, v2.y, 10F)
|
||||
@@ -116,396 +184,326 @@ class StatWidget(
|
||||
RenderSystem.setShaderColor(1F, 1F, 1F, 1F)
|
||||
}
|
||||
|
||||
private fun drawStatHexagon(stats: Map<Stat, Int>, colour: Vector3f, maximum: Int) {
|
||||
val hexLeftX = x + 25.5
|
||||
val hexTopY = y + 22
|
||||
val hexAttackY = hexTopY + 24.5
|
||||
val hexDefenceY = hexAttackY + 47.0
|
||||
val hexBottomY = hexDefenceY + 24.5
|
||||
val hexRightX = x + 108.5
|
||||
val hexCenterX = (hexLeftX + hexRightX) / 2
|
||||
val hexCenterY = (hexTopY + hexBottomY) / 2
|
||||
val minTriangleSize = 8F
|
||||
val minXTriangleLen = sin(Math.toRadians(61.0)).toFloat() * minTriangleSize * 0.95F
|
||||
val minYTriangleLen = cos(Math.toRadians(60.0)).toFloat() * minTriangleSize
|
||||
/**
|
||||
* Render a 5 or 6 sided polygon
|
||||
*
|
||||
* @param ratios list of ratios for how far each vertex is from the center, starting from top vertex going clockwise
|
||||
* @param colour the colour to render
|
||||
*/
|
||||
private fun drawStatPolygon(ratios: List<Float>, colour: Vector3f) {
|
||||
val sides = ratios.size
|
||||
if (sides !in 5 .. 6) return
|
||||
|
||||
val triangleLongEdge = (hexCenterY - hexTopY - minTriangleSize).toFloat()
|
||||
val triangleMediumEdge = (triangleLongEdge * sin(Math.toRadians(61.0))).toFloat()
|
||||
val triangleShortEdge = (triangleLongEdge * cos(Math.toRadians(61.0))).toFloat()
|
||||
val topVertexY = y + 22F
|
||||
val centerX = x + 67F
|
||||
val centerY = topVertexY + if (sides > 5) 48F else 49F
|
||||
|
||||
val hpRatio = (stats.getOrDefault(Stats.HP, 0).toFloat() / maximum).coerceIn(0F, 1F)
|
||||
val atkRatio = (stats.getOrDefault(Stats.ATTACK, 0).toFloat() / maximum).coerceIn(0F, 1F)
|
||||
val defRatio = (stats.getOrDefault(Stats.DEFENCE, 0).toFloat() / maximum).coerceIn(0F, 1F)
|
||||
val spAtkRatio = (stats.getOrDefault(Stats.SPECIAL_ATTACK, 0).toFloat() / maximum).coerceIn(0F, 1F)
|
||||
val spDefRatio = (stats.getOrDefault(Stats.SPECIAL_DEFENCE, 0).toFloat() / maximum).coerceIn(0F, 1F)
|
||||
val spdRatio = (stats.getOrDefault(Stats.SPEED, 0).toFloat() / maximum).coerceIn(0F, 1F)
|
||||
val radius = centerY - topVertexY
|
||||
|
||||
val hpPoint = Vec2(
|
||||
hexCenterX.toFloat(),
|
||||
hexCenterY.toFloat() - minTriangleSize - hpRatio * triangleLongEdge
|
||||
)
|
||||
val startAngleDeg = -90.0
|
||||
val angleStepDeg = 360.0 / sides
|
||||
|
||||
val attackPoint = Vec2(
|
||||
hexCenterX.toFloat() + minXTriangleLen + atkRatio * triangleMediumEdge,
|
||||
hexCenterY.toFloat() - minYTriangleLen - atkRatio * triangleShortEdge
|
||||
)
|
||||
// Generate the angles for each vertex
|
||||
val anglesDeg = List(sides) { i -> startAngleDeg + i * angleStepDeg }
|
||||
val anglesRad = anglesDeg.map { Math.toRadians(it) }
|
||||
|
||||
val defencePoint = Vec2(
|
||||
hexCenterX.toFloat() + minXTriangleLen + defRatio * triangleMediumEdge,
|
||||
hexCenterY.toFloat() + minYTriangleLen + defRatio * triangleShortEdge
|
||||
)
|
||||
|
||||
val specialAttackPoint = Vec2(
|
||||
hexCenterX.toFloat() - minXTriangleLen - spAtkRatio * triangleMediumEdge,
|
||||
hexCenterY.toFloat() - minYTriangleLen - spAtkRatio * triangleShortEdge
|
||||
)
|
||||
|
||||
val specialDefencePoint = Vec2(
|
||||
hexCenterX.toFloat() - minXTriangleLen - spDefRatio * triangleMediumEdge,
|
||||
hexCenterY.toFloat() + minYTriangleLen + spDefRatio * triangleShortEdge
|
||||
)
|
||||
|
||||
val speedPoint = Vec2(
|
||||
hexCenterX.toFloat(),
|
||||
hexCenterY.toFloat() + minTriangleSize + spdRatio * triangleLongEdge
|
||||
)
|
||||
|
||||
val centerPoint = Vec2(
|
||||
hexCenterX.toFloat(),
|
||||
hexCenterY.toFloat()
|
||||
)
|
||||
|
||||
// 1-o'clock
|
||||
drawTriangle(colour, hpPoint, centerPoint, attackPoint)
|
||||
// 3-o'clock
|
||||
drawTriangle(colour, attackPoint, centerPoint, defencePoint)
|
||||
// 5-o'clock
|
||||
drawTriangle(colour, defencePoint, centerPoint, speedPoint)
|
||||
// 7-o'clock
|
||||
drawTriangle(colour, speedPoint, centerPoint, specialDefencePoint)
|
||||
// 9-o'clock
|
||||
drawTriangle(colour, specialDefencePoint, centerPoint, specialAttackPoint)
|
||||
// 11-o'clock
|
||||
drawTriangle(colour, specialAttackPoint, centerPoint, hpPoint)
|
||||
}
|
||||
|
||||
private fun drawFriendship(moduleX: Int, moduleY: Int, matrices: PoseStack, context: GuiGraphics, friendship: Int) {
|
||||
val barRatio = friendship / 255F
|
||||
val barWidth = ceil(barRatio * 108)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = statsOtherBarTemplate,
|
||||
x = moduleX,
|
||||
y = moduleY,
|
||||
height = 28,
|
||||
width = 124
|
||||
)
|
||||
|
||||
val red = 1
|
||||
val green: Number = if (pokemon.friendship >= 160) 0.28 else 0.56
|
||||
val blue: Number = if (pokemon.friendship >= 160) 0.4 else 0.64
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = moduleX + 8,
|
||||
y = moduleY + 18,
|
||||
height = 8,
|
||||
width = barWidth,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue
|
||||
)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = friendshipOverlayResource,
|
||||
x = moduleX / SCALE,
|
||||
y = (moduleY + 16) / SCALE,
|
||||
height = 20,
|
||||
width = 248,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
// Label
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.stats.friendship").bold(),
|
||||
x = moduleX + 62,
|
||||
y = moduleY + 2.5,
|
||||
centered = true,
|
||||
shadow = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = friendship.toString().text(),
|
||||
x = moduleX + 11,
|
||||
y = moduleY + 6,
|
||||
scale = SCALE,
|
||||
centered = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = "${floor(barRatio * 100)}%".text(),
|
||||
x = moduleX + 113,
|
||||
y = moduleY + 6,
|
||||
scale = SCALE,
|
||||
centered = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun drawFullness(moduleX: Int, moduleY: Int, matrices: PoseStack, context: GuiGraphics, pokemon: Pokemon) {
|
||||
val currentFullness = pokemon.currentFullness
|
||||
val maxFullness = pokemon.getMaxFullness()
|
||||
val barRatio = currentFullness.toFloat() / maxFullness.toFloat()
|
||||
val barWidth = ceil(barRatio * 108)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = statsOtherBarTemplate,
|
||||
x = moduleX,
|
||||
y = moduleY,
|
||||
height = 28,
|
||||
width = 124
|
||||
)
|
||||
|
||||
val (red, green, blue) = when {
|
||||
barRatio <= 0.33 -> Triple(0f, 1f, 0f) // Green (full green)
|
||||
barRatio <= 0.66 -> Triple(1f, 1f, 0f) // Yellow (red + green)
|
||||
else -> Triple(1f, 0f, 0f) // Red (full red)
|
||||
// Calculate maximum points on the circle
|
||||
val maxPoints = anglesRad.map { angle ->
|
||||
Vec2(
|
||||
centerX + radius * Math.cos(angle).toFloat(),
|
||||
centerY + radius * Math.sin(angle).toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = moduleX + 8,
|
||||
y = moduleY + 18,
|
||||
height = 8,
|
||||
width = barWidth,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue
|
||||
)
|
||||
// Coerce values as 0.0 will prevent triangles from rendering
|
||||
val coercedRatios = ratios.map { it.coerceIn(5 / radius, 1F) }
|
||||
|
||||
// Draw the overlay
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = fullnessOverlayResource,
|
||||
x = moduleX / SCALE,
|
||||
y = (moduleY + 16) / SCALE,
|
||||
height = 20,
|
||||
width = 248,
|
||||
scale = SCALE
|
||||
)
|
||||
// Interpolate vertices based on ratios
|
||||
val vertices = maxPoints.mapIndexed { index, maxPoint ->
|
||||
Vec2(
|
||||
centerX + (maxPoint.x - centerX) * coercedRatios[index],
|
||||
centerY + (maxPoint.y - centerY) * coercedRatios[index]
|
||||
)
|
||||
}
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = "Fullness".text().bold(),
|
||||
x = moduleX + 62,
|
||||
y = moduleY + 2.5,
|
||||
centered = true,
|
||||
shadow = true
|
||||
)
|
||||
val centerPoint = Vec2(centerX, centerY)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = currentFullness.toString().text(),
|
||||
x = moduleX + 11,
|
||||
y = moduleY + 6,
|
||||
scale = SCALE,
|
||||
centered = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = "${floor(barRatio * 100)}%".text(),
|
||||
x = moduleX + 113,
|
||||
y = moduleY + 6,
|
||||
scale = SCALE,
|
||||
centered = true
|
||||
)
|
||||
// Draw triangles between each vertex and the next clockwise starting from top vertex
|
||||
RenderSystem.disableDepthTest()
|
||||
for (i in vertices.indices) {
|
||||
val nextIndex = (i + 1) % vertices.size
|
||||
drawTriangle(colour, vertices[i], centerPoint, vertices[nextIndex])
|
||||
}
|
||||
RenderSystem.enableDepthTest()
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
val renderChart = statOptions.get(statTabIndex) != OTHER
|
||||
val renderOtherStats = statOptions.get(statTabIndex) == OTHER
|
||||
val renderPentagonStats = statOptions.get(statTabIndex) == RIDE
|
||||
val matrices = context.pose()
|
||||
|
||||
// Background
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = if (renderChart) statsBaseResource else statsOtherBaseResource,
|
||||
texture = if (renderOtherStats) statsOtherBaseResource else statsBaseResource,
|
||||
x= x,
|
||||
y = y,
|
||||
width = width,
|
||||
height = height
|
||||
)
|
||||
|
||||
// Chart
|
||||
if (renderChart) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = statsChartResource,
|
||||
x= (x + 25.5) / SCALE,
|
||||
y = (y + 22) / SCALE,
|
||||
width = 166,
|
||||
height = 192,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
when (statOptions.get(statTabIndex)) {
|
||||
STATS -> drawStatHexagon(
|
||||
mapOf(
|
||||
Stats.HP to pokemon.maxHealth,
|
||||
Stats.ATTACK to pokemon.attack,
|
||||
Stats.DEFENCE to pokemon.defence,
|
||||
Stats.SPECIAL_ATTACK to pokemon.specialAttack,
|
||||
Stats.SPECIAL_DEFENCE to pokemon.specialDefence,
|
||||
Stats.SPEED to pokemon.speed
|
||||
),
|
||||
colour = Vector3f(50F/255, 215F/255F, 1F),
|
||||
maximum = 400
|
||||
)
|
||||
IV -> drawStatHexagon(
|
||||
effectiveBattleIVs,
|
||||
colour = Vector3f(216F/255, 100F/255, 1F),
|
||||
maximum = 31
|
||||
)
|
||||
EV -> drawStatHexagon(
|
||||
pokemon.evs.associate { it.key to it.value },
|
||||
colour = Vector3f(1F, 1F, 100F/255),
|
||||
maximum = 252
|
||||
)
|
||||
}
|
||||
if (renderOtherStats) {
|
||||
val barOffsetY = 29
|
||||
val barPosX = x + 9F
|
||||
var drawY = y + 15F
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = statsLabel.bold(),
|
||||
x = x + 31,
|
||||
y = y + 143,
|
||||
scale = SCALE,
|
||||
colour = if (statOptions.get(statTabIndex) == STATS) WHITE else GREY,
|
||||
centered = true
|
||||
)
|
||||
val featuresList: MutableList<Any> = renderableFeatures.toMutableList()
|
||||
featuresList.addAll(0, universalFeatures)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = ivLabel.bold(),
|
||||
x = x + 55,
|
||||
y = y + 143,
|
||||
scale = SCALE,
|
||||
colour = if (statOptions.get(statTabIndex) == IV) WHITE else GREY,
|
||||
centered = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = evLabel.bold(),
|
||||
x = x + 79,
|
||||
y = y + 143,
|
||||
scale = SCALE,
|
||||
colour = if (statOptions.get(statTabIndex) == EV) WHITE else GREY,
|
||||
centered = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = otherLabel.bold(),
|
||||
x = x + 103,
|
||||
y = y + 143,
|
||||
scale = SCALE,
|
||||
colour = if (statOptions.get(statTabIndex) == OTHER) WHITE else GREY,
|
||||
centered = true
|
||||
)
|
||||
|
||||
val paddingLeft = (WIDTH - ((statOptions.size + 1) * statTabWidth)) / 2
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
texture = tabMarkerResource,
|
||||
x= ((x + paddingLeft + ((statTabIndex + 1) * statTabWidth)) / SCALE) - 2,
|
||||
y = (y + 140) / SCALE,
|
||||
width = 8,
|
||||
height = 4,
|
||||
scale = SCALE,
|
||||
)
|
||||
|
||||
if (renderChart) {
|
||||
// Stat Labels
|
||||
renderTextAtVertices(
|
||||
context = context,
|
||||
hp = hpLabel.bold(),
|
||||
spAtk = spAtkLabel.bold(),
|
||||
atk = atkLabel.bold(),
|
||||
spDef = spDefLabel.bold(),
|
||||
def = defLabel.bold(),
|
||||
speed = speedLabel.bold()
|
||||
val pageFeatures = featuresList.subList(
|
||||
otherStatsPageIndex * OTHER_STAT_BARS_PER_PAGE,
|
||||
minOf((otherStatsPageIndex * OTHER_STAT_BARS_PER_PAGE) + OTHER_STAT_BARS_PER_PAGE, featuresList.size)
|
||||
)
|
||||
|
||||
// Stat Values
|
||||
renderTextAtVertices(
|
||||
context = context,
|
||||
offsetY = 5.5,
|
||||
enableColour = false,
|
||||
hp = getStatValueAsText(Stats.HP),
|
||||
spAtk = getStatValueAsText(Stats.SPECIAL_ATTACK),
|
||||
atk = getStatValueAsText(Stats.ATTACK),
|
||||
spDef = getStatValueAsText(Stats.SPECIAL_DEFENCE),
|
||||
def = getStatValueAsText(Stats.DEFENCE),
|
||||
speed = getStatValueAsText(Stats.SPEED)
|
||||
)
|
||||
|
||||
// Nature-modified Stat Icons
|
||||
if (statOptions.get(statTabIndex) == STATS) {
|
||||
val nature = pokemon.effectiveNature
|
||||
renderModifiedStatIcon(matrices, nature.increasedStat, true)
|
||||
renderModifiedStatIcon(matrices, nature.decreasedStat, false)
|
||||
for (feature in pageFeatures) {
|
||||
if (feature is BarSummarySpeciesFeatureRenderer) {
|
||||
val rendered = feature.render(
|
||||
guiGraphics = context,
|
||||
x = barPosX,
|
||||
y = drawY,
|
||||
pokemon = pokemon
|
||||
)
|
||||
if (rendered) drawY += barOffsetY
|
||||
}
|
||||
}
|
||||
if (featuresList.size > 4) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = statsOtherSidebarsResource,
|
||||
x= x,
|
||||
y = y + 13,
|
||||
width = 134,
|
||||
height = 115
|
||||
)
|
||||
otherStatLeftButton?.renderWidget(context, pMouseX, pMouseY, pPartialTicks)
|
||||
otherStatRightButton?.renderWidget(context, pMouseX, pMouseY, pPartialTicks)
|
||||
}
|
||||
} else {
|
||||
var drawY = y + 11
|
||||
|
||||
drawFriendship(x + 5, drawY, matrices, context, pokemon.friendship)
|
||||
drawY += 30
|
||||
|
||||
drawFullness(x + 5, drawY, matrices, context, pokemon)
|
||||
drawY += 30
|
||||
|
||||
for (renderableFeature in renderableFeatures) {
|
||||
val rendered = renderableFeature.render(
|
||||
GuiGraphics = context,
|
||||
x = x + 5F,
|
||||
y = drawY.toFloat(),
|
||||
pokemon = pokemon
|
||||
if (renderPentagonStats) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = statsChartPentagonResource,
|
||||
x= (x + 20.5) / SCALE,
|
||||
y = (y + 22) / SCALE,
|
||||
width = 186,
|
||||
height = 176,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
if (rendered) {
|
||||
drawY += 30
|
||||
pokemon.form.riding.behaviours?.let {
|
||||
val behaviours = it.entries.toList()
|
||||
val selectedBehaviour = behaviours[rideBehaviourIndex]
|
||||
|
||||
val pentagonColour = when (selectedBehaviour.key) {
|
||||
RidingStyle.AIR -> {
|
||||
if (behaviours.size > 1 && centerHovered(pMouseX, pMouseY))
|
||||
Vector3f(70F/255F, 235F/225F, 195F/255F)
|
||||
else Vector3f(40F/255F, 205F/255F, 165F/255F)
|
||||
}
|
||||
RidingStyle.LIQUID -> {
|
||||
if (behaviours.size > 1 && centerHovered(pMouseX, pMouseY))
|
||||
Vector3f(95F/255F, 165F/255F, 1F)
|
||||
else Vector3f(65F/255F, 135F/255F, 1F)
|
||||
}
|
||||
else -> {
|
||||
if (behaviours.size > 1 && centerHovered(pMouseX, pMouseY))
|
||||
Vector3f(1F, 195F/255F, 30F/255F)
|
||||
else Vector3f(1F, 165F/255F, 0F)
|
||||
}
|
||||
}
|
||||
|
||||
drawStatPolygon(
|
||||
ratios = RidingStat.entries.map { pokemon.getRideStat(selectedBehaviour.key, it) / 100F },
|
||||
colour = pentagonColour
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.ride_style.${selectedBehaviour.key.name.lowercase()}").bold(),
|
||||
x = x + (WIDTH / 2),
|
||||
y = y + 66,
|
||||
shadow = true,
|
||||
centered = true
|
||||
)
|
||||
|
||||
// Stat Labels
|
||||
renderPolygonLabels(
|
||||
context = context,
|
||||
labels = RidingStat.entries.toList().map { stat ->
|
||||
if (statLabelsHovered(pentagonVerticesOffset, pMouseX, pMouseY))
|
||||
"${floor(pokemon.getRideStat(selectedBehaviour.key, stat))}/${selectedBehaviour.value.stats[stat]?.endInclusive}".text()
|
||||
else lang("ui.stats.ride.${stat.name.lowercase()}").bold()
|
||||
},
|
||||
verticesOffset = pentagonVerticesOffset
|
||||
)
|
||||
|
||||
// Stat Values
|
||||
renderPolygonLabels(
|
||||
context = context,
|
||||
labels = RidingStat.entries.toList().map { stat ->
|
||||
if (statLabelsHovered(pentagonVerticesOffset, pMouseX, pMouseY))
|
||||
"${floor((pokemon.getRideStat(selectedBehaviour.key, stat) / (selectedBehaviour.value.stats[stat]?.endInclusive ?: 1)) * 100)}%".text()
|
||||
else floor(pokemon.getRideStat(selectedBehaviour.key, stat)).toString().text()
|
||||
},
|
||||
verticesOffset = pentagonVerticesOffset,
|
||||
offsetY = 5.5
|
||||
)
|
||||
}
|
||||
|
||||
} else {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = statsChartResource,
|
||||
x= (x + 25.5) / SCALE,
|
||||
y = (y + 22) / SCALE,
|
||||
width = 166,
|
||||
height = 192,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
when (statOptions.get(statTabIndex)) {
|
||||
STATS -> drawStatPolygon(
|
||||
listOf(
|
||||
pokemon.maxHealth,
|
||||
pokemon.attack,
|
||||
pokemon.defence,
|
||||
pokemon.speed,
|
||||
pokemon.specialDefence,
|
||||
pokemon.specialAttack
|
||||
).map { it / 400F },
|
||||
colour = Vector3f(50F/255F, 215F/255F, 1F)
|
||||
)
|
||||
IV -> drawStatPolygon(
|
||||
statLabels.values.map { pokemon.ivs.getEffectiveBattleIV(it) / 31F },
|
||||
colour = Vector3f(216F/255, 100F/255, 1F)
|
||||
)
|
||||
EV -> drawStatPolygon(
|
||||
statLabels.values.map { (pokemon.evs[it]?.toFloat() ?: 0F) / 252F },
|
||||
colour = Vector3f(1F, 1F, 100F/255F)
|
||||
)
|
||||
}
|
||||
|
||||
val labelsHovered = statLabelsHovered(hexagonVerticesOffset, pMouseX, pMouseY)
|
||||
|
||||
val labels = statLabels.map { stat ->
|
||||
if (labelsHovered) {
|
||||
when (statOptions.get(statTabIndex)) {
|
||||
IV -> {
|
||||
"${
|
||||
if (pokemon.ivs.isHyperTrained(stat.value)) "${pokemon.ivs[stat.value]} (${pokemon.ivs.hyperTrainedIVs[stat.value]})"
|
||||
else pokemon.ivs[stat.value].toString()
|
||||
}/31".text()
|
||||
}
|
||||
EV -> "${pokemon.evs.getOrDefault(stat.value)}/252".text()
|
||||
else -> stat.key
|
||||
}
|
||||
} else { stat.key }
|
||||
}
|
||||
|
||||
// Stat Labels
|
||||
renderPolygonLabels(
|
||||
context = context,
|
||||
labels = labels,
|
||||
verticesOffset = hexagonVerticesOffset,
|
||||
enableColour = true
|
||||
)
|
||||
|
||||
// Stat Values
|
||||
renderPolygonLabels(
|
||||
context = context,
|
||||
labels = statValuesAsText(
|
||||
statLabels.values.toList(),
|
||||
labelsHovered
|
||||
),
|
||||
verticesOffset = hexagonVerticesOffset,
|
||||
offsetY = 5.5,
|
||||
enableColour = true
|
||||
)
|
||||
|
||||
// Nature-modified Stat Icons
|
||||
if (statOptions.get(statTabIndex) == STATS) {
|
||||
val nature = pokemon.effectiveNature
|
||||
renderModifiedStatIcon(matrices, nature.increasedStat, true)
|
||||
renderModifiedStatIcon(matrices, nature.decreasedStat, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stat type select bar
|
||||
val hasRideBehaviour = pokemon.form.riding.behaviours != null
|
||||
val startPosX = x + if (hasRideBehaviour) 23 else 31
|
||||
val statTabWidth = if (hasRideBehaviour) STAT_TAB_WIDTH_6 else STAT_TAB_WIDTH_5
|
||||
|
||||
statOptions.forEachIndexed { index, stat ->
|
||||
val statKey = if (stat == STATS) "" else ".$stat"
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = lang("ui.stats$statKey").bold(),
|
||||
x = startPosX + (statTabWidth * index),
|
||||
y = y + 143,
|
||||
scale = SCALE,
|
||||
colour = if (statOptions.get(statTabIndex) == stat) WHITE else GREY,
|
||||
centered = true
|
||||
)
|
||||
}
|
||||
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
texture = tabMarkerResource,
|
||||
x= (startPosX + (statTabIndex * statTabWidth) - (MARKER_WIDTH / 4)) / SCALE,
|
||||
y = (y + 140) / SCALE,
|
||||
width = MARKER_WIDTH,
|
||||
height = 4,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
val index = getTabIndexFromPos(pMouseX, pMouseY)
|
||||
// Only play sound here as the rest of the widget is meant to be silent
|
||||
if (index in 0..4 && statTabIndex != index) {
|
||||
if (index in 0 until statOptions.size && statTabIndex != index) {
|
||||
statTabIndex = index
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
|
||||
if (statOptions.get(statTabIndex) == RIDE && ((pokemon.riding.behaviours?.size ?: 0) > 1) && centerHovered(pMouseX, pMouseY)) {
|
||||
rideBehaviourIndex = (rideBehaviourIndex + 1) % (pokemon.riding.behaviours?.size ?: 1)
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
|
||||
return super.mouseClicked(pMouseX, pMouseY, pButton)
|
||||
}
|
||||
|
||||
private fun getStatValueAsText(stat: Stat): MutableComponent {
|
||||
val value = when (statOptions.get(statTabIndex)) {
|
||||
STATS -> if (stat == Stats.HP) "${pokemon.currentHealth} / ${pokemon.maxHealth}" else pokemon.getStat(stat).toString()
|
||||
IV -> if (pokemon.ivs.isHyperTrained(stat)) "${pokemon.ivs[stat]} (${pokemon.ivs.hyperTrainedIVs[stat]})" else pokemon.ivs[stat].toString()
|
||||
EV -> pokemon.evs.getOrDefault(stat).toString()
|
||||
else -> "0"
|
||||
private fun statValuesAsText(stats: List<Stat>, asPercent: Boolean): List<MutableComponent> {
|
||||
return stats.map { stat ->
|
||||
when (statOptions.get(statTabIndex)) {
|
||||
STATS -> (if (stat == Stats.HP) "${pokemon.currentHealth} / ${pokemon.maxHealth}" else pokemon.getStat(stat).toString()).text()
|
||||
IV -> {
|
||||
(if (asPercent) {
|
||||
"${floor((((if (pokemon.ivs.isHyperTrained(stat)) pokemon.ivs.hyperTrainedIVs[stat] else pokemon.ivs[stat]) ?: 0) / 31.0) * 100)}%"
|
||||
} else {
|
||||
if (pokemon.ivs.isHyperTrained(stat)) "${pokemon.ivs[stat]} (${pokemon.ivs.hyperTrainedIVs[stat]})"
|
||||
else pokemon.ivs[stat].toString()
|
||||
}).text()
|
||||
}
|
||||
EV -> {
|
||||
(if (asPercent) "${floor((pokemon.evs.getOrDefault(stat) / 252.0) * 100)}%"
|
||||
else pokemon.evs.getOrDefault(stat).toString()).text()
|
||||
}
|
||||
else -> "0".text()
|
||||
}
|
||||
}
|
||||
return value.text()
|
||||
}
|
||||
|
||||
private fun renderModifiedStatIcon(pPoseStack: PoseStack, stat: Stat?, increasedStat: Boolean) {
|
||||
@@ -534,7 +532,7 @@ class StatWidget(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getModifiedStatColour(stat: Stat, enableColour: Boolean): Int {
|
||||
private fun getModifiedStatColour(stat: Stat?, enableColour: Boolean): Int {
|
||||
if (statOptions.get(statTabIndex) == STATS && enableColour) {
|
||||
val nature = pokemon.effectiveNature
|
||||
|
||||
@@ -544,81 +542,38 @@ class StatWidget(
|
||||
return WHITE
|
||||
}
|
||||
|
||||
private fun renderTextAtVertices(
|
||||
context: GuiGraphics,
|
||||
offsetY: Double = 0.0,
|
||||
enableColour: Boolean = true,
|
||||
hp: MutableComponent,
|
||||
spAtk: MutableComponent,
|
||||
atk: MutableComponent,
|
||||
spDef: MutableComponent,
|
||||
def: MutableComponent,
|
||||
speed: MutableComponent
|
||||
) {
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = hp,
|
||||
x = x + 67,
|
||||
y = y + 10.5 + offsetY,
|
||||
scale = SCALE,
|
||||
colour = getModifiedStatColour(Stats.HP, enableColour),
|
||||
centered = true
|
||||
)
|
||||
private fun renderPolygonLabels(context: GuiGraphics, labels: List<MutableComponent>, verticesOffset: List<Pair<Double, Double>>, offsetY: Double = 0.0, enableColour: Boolean = false) {
|
||||
if (labels.size != verticesOffset.size) return
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = spAtk,
|
||||
x = x + 12,
|
||||
y = y + 42.5 + offsetY,
|
||||
scale = SCALE,
|
||||
colour = getModifiedStatColour(Stats.SPECIAL_ATTACK, enableColour),
|
||||
centered = true
|
||||
)
|
||||
labels.forEachIndexed { index, label ->
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = label,
|
||||
x = x + verticesOffset[index].first,
|
||||
y = y + verticesOffset[index].second + offsetY,
|
||||
scale = SCALE,
|
||||
colour = getModifiedStatColour(statLabels[label], enableColour),
|
||||
centered = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = atk,
|
||||
x = x + 122,
|
||||
y = y + 42.5 + offsetY,
|
||||
scale = SCALE,
|
||||
colour = getModifiedStatColour(Stats.ATTACK,enableColour),
|
||||
centered = true
|
||||
)
|
||||
private fun centerHovered(pMouseX: Number, pMouseY: Number): Boolean {
|
||||
return (pMouseX.toInt() in (x + 44)..(x + 90)) && (pMouseY.toInt() in (y + 47)..(y + 93))
|
||||
}
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = spDef,
|
||||
x = x + 12,
|
||||
y = y + 93.5 + offsetY,
|
||||
scale = SCALE,
|
||||
colour = getModifiedStatColour(Stats.SPECIAL_DEFENCE, enableColour),
|
||||
centered = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = def,
|
||||
x = x + 122,
|
||||
y = y + 93.5 + offsetY,
|
||||
scale = SCALE,
|
||||
colour = getModifiedStatColour(Stats.DEFENCE, enableColour),
|
||||
centered = true
|
||||
)
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = speed,
|
||||
x = x + 67,
|
||||
y = y + 124.5 + offsetY,
|
||||
scale = SCALE,
|
||||
colour = getModifiedStatColour(Stats.SPEED, enableColour),
|
||||
centered = true
|
||||
)
|
||||
private fun statLabelsHovered(labelOffsets: List<Pair<Double, Double>>, mouseX: Int, mouseY: Int): Boolean {
|
||||
return labelOffsets.any { pos ->
|
||||
(mouseX.toDouble() in (x + pos.first - 12)..(x + pos.first + 12))
|
||||
&& (mouseY.toDouble() in (y + pos.second - 1)..(y + pos.second + 10))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTabIndexFromPos(mouseX: Double, mouseY: Double): Int {
|
||||
val paddingLeft = ((WIDTH - ((statOptions.size + 1) * statTabWidth)) / 2.0) + (statTabWidth / 2)
|
||||
val left = x + paddingLeft
|
||||
val hasRideBehaviour = pokemon.form.riding.behaviours != null
|
||||
val left = x + if (hasRideBehaviour) ((23 + 1) / 2).toFloat() else ((31 + 1) / 2).toFloat()
|
||||
val statTabWidth = if (hasRideBehaviour) STAT_TAB_WIDTH_6 else STAT_TAB_WIDTH_5
|
||||
|
||||
val top = y + 140.0
|
||||
if (mouseX in left..(left + (statTabWidth * (statOptions.size + 1))) && mouseY in top..(top + 9.0)) {
|
||||
var startX = left
|
||||
@@ -631,4 +586,4 @@ class StatWidget(
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.features
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.BarSummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
|
||||
class FriendshipFeatureRenderer(
|
||||
val selectedPokemon: Pokemon
|
||||
) : BarSummarySpeciesFeatureRenderer(
|
||||
"friendship",
|
||||
lang("ui.stats.friendship"),
|
||||
cobblemonResource("textures/gui/summary/summary_stats_other_bar.png"),
|
||||
cobblemonResource("textures/gui/summary/summary_stats_friendship_overlay.png"),
|
||||
selectedPokemon,
|
||||
0,
|
||||
255,
|
||||
selectedPokemon.friendship
|
||||
) {
|
||||
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon): Boolean {
|
||||
renderElement(guiGraphics, x, y, pokemon)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun renderBar(guiGraphics: GuiGraphics, x: Float, y: Float, barValue: Int, barRatio: Float, barWidth: Int) {
|
||||
val red = 1
|
||||
val green: Number = if (barValue >= 160) 0.28 else 0.56
|
||||
val blue: Number = if (barValue >= 160) 0.4 else 0.64
|
||||
|
||||
blitk(
|
||||
matrixStack = guiGraphics.pose(),
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = x + 3,
|
||||
y = y + 13,
|
||||
height = 10,
|
||||
width = barWidth,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue
|
||||
)
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.features
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.summary.featurerenderers.BarSummarySpeciesFeatureRenderer
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
|
||||
class FullnessFeatureRenderer(
|
||||
val selectedPokemon: Pokemon
|
||||
) : BarSummarySpeciesFeatureRenderer(
|
||||
"fullness",
|
||||
lang("ui.stats.fullness"),
|
||||
cobblemonResource("textures/gui/summary/summary_stats_other_bar.png"),
|
||||
cobblemonResource("textures/gui/summary/summary_stats_fullness_overlay.png"),
|
||||
selectedPokemon,
|
||||
0,
|
||||
selectedPokemon.getMaxFullness(),
|
||||
selectedPokemon.currentFullness
|
||||
) {
|
||||
override fun render(guiGraphics: GuiGraphics, x: Float, y: Float, pokemon: Pokemon): Boolean {
|
||||
renderElement(guiGraphics, x, y, pokemon)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun renderBar(guiGraphics: GuiGraphics, x: Float, y: Float, barValue: Int, barRatio: Float, barWidth: Int) {
|
||||
val (red, green, blue) = when {
|
||||
barRatio <= 0.33 -> Triple(120F/255F, 200F/255F, 80F/255F) // Green
|
||||
barRatio <= 0.66 -> Triple(240F/255F, 200F/255F, 65F/255F) // Yellow
|
||||
else -> Triple(230F/255F, 80F/255F, 65F/255F) // Red
|
||||
}
|
||||
|
||||
blitk(
|
||||
matrixStack = guiGraphics.pose(),
|
||||
texture = CobblemonResources.WHITE,
|
||||
x = x + 3,
|
||||
y = y + 13,
|
||||
height = 10,
|
||||
width = barWidth,
|
||||
red = red,
|
||||
green = green,
|
||||
blue = blue
|
||||
)
|
||||
}
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.net.data
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
internal object UnlockReloadPacketHandler : ClientNetworkPacketHandler<UnlockReloadPacket> {
|
||||
override fun handle(packet: UnlockReloadPacket, client: Minecraft) {
|
||||
CobblemonDataProvider.canReload = true
|
||||
}
|
||||
}
|
||||
+92
-3
@@ -9,30 +9,63 @@
|
||||
package com.cobblemon.mod.common.client.render.player
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.riding.RidingAnimation
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.model.AnimationUtils
|
||||
import net.minecraft.client.model.HumanoidModel
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.player.AbstractClientPlayer
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.HumanoidArm
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* @author landonjw
|
||||
*/
|
||||
object MountedPlayerRenderer {
|
||||
@JvmField
|
||||
var shouldApplyRootAnimation = false
|
||||
|
||||
@JvmField
|
||||
val relevantPartsByName = mutableMapOf(
|
||||
"body" to ModelPart(emptyList(), emptyMap()),
|
||||
)
|
||||
|
||||
val defaultAnimations = listOf(
|
||||
RidingAnimation(
|
||||
fileName = "player",
|
||||
animationName = "animation.player.default_ride_pose"
|
||||
)
|
||||
)
|
||||
|
||||
fun animate(
|
||||
model: HumanoidModel<AbstractClientPlayer>,
|
||||
pokemonEntity: PokemonEntity,
|
||||
player: AbstractClientPlayer,
|
||||
relevantPartsByName: Map<String, ModelPart>,
|
||||
headYaw: Float,
|
||||
headPitch: Float,
|
||||
ageInTicks: Float,
|
||||
limbSwing: Float,
|
||||
limbSwingAmount: Float
|
||||
) {
|
||||
// We need to reset the root because it's a synthetic part, Minecraft won't do this for us.
|
||||
val root = relevantPartsByName["body"] ?: return
|
||||
root.x = 0F
|
||||
root.y = 0F
|
||||
root.z = 0F
|
||||
root.xRot = 0F
|
||||
root.yRot = 0F
|
||||
root.zRot = 0F
|
||||
|
||||
val seatIndex = pokemonEntity.passengers.indexOf(player).takeIf { it != -1 && it < pokemonEntity.seats.size } ?: return
|
||||
val seat = pokemonEntity.seats[seatIndex]
|
||||
val animations = seat.poseAnimations?.firstOrNull { it.poseTypes.isEmpty() || it.poseTypes.contains(pokemonEntity.getCurrentPoseType()) }?.animations
|
||||
?: return
|
||||
val animations = seat.poseAnimations
|
||||
?.firstOrNull { it.poseTypes.isEmpty() || it.poseTypes.contains(pokemonEntity.getCurrentPoseType()) }?.animations
|
||||
?: defaultAnimations
|
||||
val state = pokemonEntity.delegate as PokemonClientDelegate
|
||||
|
||||
relevantPartsByName.values.forEach {
|
||||
@@ -44,6 +77,8 @@ object MountedPlayerRenderer {
|
||||
state.runtime.environment.setSimpleVariable("age_in_ticks", DoubleValue(ageInTicks.toDouble()))
|
||||
state.runtime.environment.setSimpleVariable("limb_swing", DoubleValue(limbSwing.toDouble()))
|
||||
state.runtime.environment.setSimpleVariable("limb_swing_amount", DoubleValue(limbSwingAmount.toDouble()))
|
||||
state.runtime.environment.setSimpleVariable("head_yaw", DoubleValue(headYaw.toDouble()))
|
||||
state.runtime.environment.setSimpleVariable("head_pitch", DoubleValue(headPitch.toDouble()))
|
||||
|
||||
// TODO add the q.player reference, requires a cached thing or something on the client idk
|
||||
|
||||
@@ -61,5 +96,59 @@ object MountedPlayerRenderer {
|
||||
intensity = 1F
|
||||
)
|
||||
}
|
||||
|
||||
applyRegularAnimation(model, player, ageInTicks)
|
||||
}
|
||||
|
||||
/**
|
||||
* This does what Minecraft would typically do for various additional body part
|
||||
* rendering thingies. It's largely copy paste.
|
||||
*/
|
||||
fun applyRegularAnimation(
|
||||
model: HumanoidModel<AbstractClientPlayer>,
|
||||
player: AbstractClientPlayer,
|
||||
ageInTicks: Float
|
||||
) {
|
||||
val rightHanded = player.mainArm == HumanoidArm.RIGHT
|
||||
if (player.isUsingItem) {
|
||||
val usingMainHand = player.usedItemHand == InteractionHand.MAIN_HAND
|
||||
if (usingMainHand == rightHanded) {
|
||||
model.poseRightArm(player)
|
||||
} else {
|
||||
model.poseLeftArm(player)
|
||||
}
|
||||
} else {
|
||||
val offHandIsTwoHanded: Boolean = if (rightHanded) model.leftArmPose.isTwoHanded else model.rightArmPose.isTwoHanded
|
||||
if (rightHanded != offHandIsTwoHanded) {
|
||||
model.poseLeftArm(player)
|
||||
model.poseRightArm(player)
|
||||
} else {
|
||||
model.poseRightArm(player)
|
||||
model.poseLeftArm(player)
|
||||
}
|
||||
}
|
||||
|
||||
model.setupAttackAnimation(player, ageInTicks)
|
||||
|
||||
if (model.rightArmPose != HumanoidModel.ArmPose.SPYGLASS) {
|
||||
AnimationUtils.bobModelPart(model.rightArm, ageInTicks, 1.0F);
|
||||
}
|
||||
|
||||
if (model.leftArmPose != HumanoidModel.ArmPose.SPYGLASS) {
|
||||
AnimationUtils.bobModelPart(model.leftArm, ageInTicks, -1.0F);
|
||||
}
|
||||
|
||||
model.hat.copyFrom(model.head)
|
||||
}
|
||||
|
||||
const val RIDING_SITTING_OFFSET = -10.0
|
||||
fun animateRoot(stack: PoseStack) {
|
||||
val root = relevantPartsByName["body"] ?: return
|
||||
val rootOffset = Vec3(root.x.toDouble(), root.y.toDouble() + RIDING_SITTING_OFFSET, root.z.toDouble()).scale(1/16.0)
|
||||
val rotation = Vec3(root.xRot.toDouble(), root.yRot.toDouble(), root.zRot.toDouble())
|
||||
stack.mulPose(Axis.ZP.rotation(rotation.z.toFloat()))
|
||||
stack.mulPose(Axis.YP.rotation(rotation.y.toFloat()))
|
||||
stack.mulPose(Axis.XP.rotation(rotation.x.toFloat()))
|
||||
stack.translate(rootOffset.x.toFloat(), rootOffset.y.toFloat(), rootOffset.z.toFloat())
|
||||
}
|
||||
}
|
||||
|
||||
+2
-9
@@ -11,8 +11,6 @@ package com.cobblemon.mod.common.client.tooltips
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.CobblemonRecipeTypes
|
||||
import com.cobblemon.mod.common.api.cooking.Flavour
|
||||
import com.cobblemon.mod.common.api.cooking.Food
|
||||
import com.cobblemon.mod.common.api.cooking.PokePuffUtils
|
||||
import com.cobblemon.mod.common.api.cooking.Seasonings
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
|
||||
@@ -20,20 +18,16 @@ import com.cobblemon.mod.common.api.fishing.SpawnBaitUtils
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.text.*
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.item.components.FoodComponent
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.Style
|
||||
import net.minecraft.world.effect.MobEffectInstance
|
||||
import net.minecraft.world.effect.MobEffectUtil
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.crafting.RecipeManager
|
||||
import net.minecraft.world.level.Level
|
||||
import java.text.DecimalFormat
|
||||
|
||||
val cookingPotRecipeAbsorbHeader by lazy { lang("item_class.cooking_pot_recipe_absorbs").gray() }
|
||||
@@ -121,8 +115,7 @@ fun generateAdditionalFlavorTooltip(flavours: Map<Flavour, Int>): MutableList<Co
|
||||
|
||||
val combinedFlavorsLine = Component.literal("")
|
||||
flavours.filter { it.key != Flavour.MILD }.forEach { (flavour, value) ->
|
||||
var flavourText = lang("seasoning_flavor.${flavour.name.lowercase()}").withStyle(flavour.chatFormatting)
|
||||
|
||||
val flavourText = lang("seasoning_flavor.${flavour.name.lowercase()}").setStyle(Style.EMPTY.withColor(flavour.colour))
|
||||
if (combinedFlavorsLine.string.isNotEmpty()) {
|
||||
combinedFlavorsLine.append(" ")
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.command
|
||||
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.item.HeldItems
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
@@ -36,7 +37,7 @@ object ReloadShowdownCommand {
|
||||
ShowdownService.service.resetAllRegistries()
|
||||
ShowdownService.service.sendRegistryData(Abilities.abilityScripts, "ability")
|
||||
ShowdownService.service.sendRegistryData(BagItems.bagItemsScripts, "bagItem")
|
||||
// TODO: ShowdownService.service.sendRegistryData(notYetImplemented, "heldItem")
|
||||
ShowdownService.service.sendRegistryData(HeldItems.heldItemsScripts, "heldItem")
|
||||
ShowdownService.service.sendRegistryData(Moves.moveScripts, "move")
|
||||
ShowdownService.service.sendRegistryData(PokemonSpecies.allShowdownSpecies(), "species")
|
||||
context.source.sendSystemMessage(Component.literal("Reloaded showdown"))
|
||||
|
||||
@@ -10,9 +10,9 @@ package com.cobblemon.mod.common.data
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.CobblemonCosmeticItems
|
||||
import com.cobblemon.mod.common.CobblemonCallbacks
|
||||
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.CobblemonUnlockableWallpapers
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
@@ -20,15 +20,15 @@ import com.cobblemon.mod.common.api.berry.Berries
|
||||
import com.cobblemon.mod.common.api.cooking.Seasonings
|
||||
import com.cobblemon.mod.common.api.data.DataProvider
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.pokedex.Dexes
|
||||
import com.cobblemon.mod.common.api.dialogue.Dialogues
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.fishing.PokeRods
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
|
||||
import com.cobblemon.mod.common.api.fishing.PokeRods
|
||||
import com.cobblemon.mod.common.api.fossil.Fossils
|
||||
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
||||
import com.cobblemon.mod.common.api.interaction.PokemonInteractions
|
||||
import com.cobblemon.mod.common.api.item.HeldItems
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
@@ -36,6 +36,7 @@ import com.cobblemon.mod.common.api.npc.NPCClasses
|
||||
import com.cobblemon.mod.common.api.npc.NPCPresets
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokedex.DexAdditions
|
||||
import com.cobblemon.mod.common.api.pokedex.Dexes
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.DexEntries
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.DexEntryAdditions
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
@@ -47,72 +48,71 @@ import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnDetailPresets
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
|
||||
import com.cobblemon.mod.common.pokemon.properties.PropertiesCompletionProvider
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import java.util.UUID
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
import net.minecraft.server.packs.resources.ResourceManagerReloadListener
|
||||
import java.util.*
|
||||
|
||||
object CobblemonDataProvider : DataProvider {
|
||||
|
||||
internal var canReload = true
|
||||
// Both Forge n Fabric keep insertion order so if a registry depends on another simply register it after
|
||||
private val registries = linkedSetOf<DataRegistry>()
|
||||
private val reloadableRegistries = linkedSetOf<DataRegistry>()
|
||||
private val synchronizedPlayerIds = mutableListOf<UUID>()
|
||||
|
||||
private val scheduledActions = mutableMapOf<UUID, MutableList<() -> Unit>>()
|
||||
|
||||
fun registerDefaults() {
|
||||
this.register(CobblemonScripts)
|
||||
this.register(SpeciesFeatures)
|
||||
this.register(GlobalSpeciesFeatures)
|
||||
this.register(SpeciesFeatureAssignments)
|
||||
this.register(ActionEffects)
|
||||
this.register(Moves)
|
||||
this.register(Abilities)
|
||||
this.register(CobblemonBehaviours)
|
||||
this.register(PokemonSpecies)
|
||||
this.register(SpeciesAdditions)
|
||||
this.register(PokeBalls)
|
||||
this.register(PropertiesCompletionProvider)
|
||||
this.register(SpawnDetailPresets)
|
||||
this.register(CobblemonSpawnRules)
|
||||
this.register(CobblemonMechanics)
|
||||
this.register(BagItems)
|
||||
this.register(Dialogues)
|
||||
this.register(NaturalMaterials)
|
||||
this.register(Fossils)
|
||||
this.register(NPCPresets)
|
||||
this.register(NPCClasses)
|
||||
this.register(DexEntries)
|
||||
this.register(DexEntryAdditions)
|
||||
this.register(Dexes)
|
||||
this.register(DexAdditions)
|
||||
this.register(CobblemonCosmeticItems)
|
||||
this.register(CobblemonCallbacks)
|
||||
this.register(CobblemonUnlockableWallpapers)
|
||||
this.register(Marks)
|
||||
this.register(StarterDataLoader)
|
||||
this.register(CobblemonScripts, reloadable = true)
|
||||
this.register(SpeciesFeatures, reloadable = false)
|
||||
this.register(GlobalSpeciesFeatures, reloadable = false)
|
||||
this.register(SpeciesFeatureAssignments, reloadable = false)
|
||||
this.register(ActionEffects, reloadable = true)
|
||||
this.register(Moves, reloadable = false)
|
||||
this.register(Abilities, reloadable = false)
|
||||
this.register(CobblemonBehaviours, reloadable = false)
|
||||
this.register(PokemonSpecies, reloadable = false)
|
||||
this.register(SpeciesAdditions, reloadable = false)
|
||||
this.register(PokeBalls, reloadable = false)
|
||||
this.register(PropertiesCompletionProvider, reloadable = false)
|
||||
this.register(SpawnDetailPresets, reloadable = true)
|
||||
this.register(CobblemonSpawnRules, reloadable = true)
|
||||
this.register(CobblemonMechanics, reloadable = true)
|
||||
this.register(BagItems, reloadable = false)
|
||||
this.register(HeldItems, reloadable = false)
|
||||
this.register(Dialogues, reloadable = true)
|
||||
this.register(NaturalMaterials, reloadable = true)
|
||||
this.register(Fossils, reloadable = true)
|
||||
this.register(NPCPresets, reloadable = false)
|
||||
this.register(NPCClasses, reloadable = false)
|
||||
this.register(DexEntries, reloadable = false)
|
||||
this.register(DexEntryAdditions, reloadable = false)
|
||||
this.register(Dexes, reloadable = false)
|
||||
this.register(DexAdditions, reloadable = false)
|
||||
this.register(CobblemonCosmeticItems, reloadable = true)
|
||||
this.register(CobblemonCallbacks, reloadable = true)
|
||||
this.register(CobblemonUnlockableWallpapers, reloadable = true)
|
||||
this.register(Marks, reloadable = false)
|
||||
this.register(StarterDataLoader, reloadable = true)
|
||||
|
||||
CobblemonSpawnPools.load()
|
||||
this.register(PokeRods)
|
||||
this.register(Berries)
|
||||
this.register(Seasonings)
|
||||
this.register(PokemonInteractions)
|
||||
this.register(SpawnBaitEffects)
|
||||
this.register(PokeRods, reloadable = false)
|
||||
this.register(Berries, reloadable = false)
|
||||
this.register(Seasonings, reloadable = false)
|
||||
this.register(PokemonInteractions, reloadable = false)
|
||||
this.register(SpawnBaitEffects, reloadable = false)
|
||||
SpawnBait.Effects.setupEffects()
|
||||
|
||||
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
|
||||
synchronizedPlayerIds.remove(it.player.uuid)
|
||||
UnlockReloadPacket().sendToPlayer(it.player)
|
||||
}
|
||||
|
||||
ifClient {
|
||||
@@ -121,12 +121,15 @@ object CobblemonDataProvider : DataProvider {
|
||||
Cobblemon.implementation.registerResourceReloader(cobblemonResource("data_resources"), SimpleResourceReloader(PackType.SERVER_DATA), PackType.SERVER_DATA, emptyList())
|
||||
}
|
||||
|
||||
override fun <T : DataRegistry> register(registry: T): T {
|
||||
override fun <T : DataRegistry> register(registry: T, reloadable: Boolean): T {
|
||||
// Only send message once
|
||||
if (this.registries.isEmpty()) {
|
||||
LOGGER.info("Note: Cobblemon data registries are only loaded once per server instance as Pokémon species are not safe to reload.")
|
||||
}
|
||||
this.registries.add(registry)
|
||||
if (reloadable) {
|
||||
this.reloadableRegistries.add(registry)
|
||||
}
|
||||
LOGGER.info("Registered the {} registry", registry.id.toString())
|
||||
LOGGER.debug("Registered the {} registry of class {}", registry.id.toString(), registry::class.qualifiedName)
|
||||
return registry
|
||||
@@ -157,15 +160,9 @@ object CobblemonDataProvider : DataProvider {
|
||||
private class SimpleResourceReloader(private val type: PackType) : ResourceManagerReloadListener {
|
||||
override fun onResourceManagerReload(manager: ResourceManager) {
|
||||
// Check for a server running, this is due to the create a world screen triggering datapack reloads, these are fine to happen as many times as needed as players may be in the process of adding their datapacks.
|
||||
val isInGame = server() != null
|
||||
if (isInGame && this.type == PackType.SERVER_DATA && !canReload) {
|
||||
return
|
||||
}
|
||||
registries.filter { it.type == this.type }
|
||||
val reloadAllowed = server()?.isReady != true
|
||||
registries.filter { it.type == this.type && (reloadAllowed || it in reloadableRegistries) }
|
||||
.forEach { it.reload(manager) }
|
||||
if (isInGame && this.type == PackType.SERVER_DATA) {
|
||||
canReload = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ class EntityCallbacks(val entity: Entity) : HashMap<ResourceLocation, MutableLis
|
||||
companion object {
|
||||
val HIT_BY_POKEBALL = cobblemonResource("hit_by_pokeball")
|
||||
val SAW_ENTITY = cobblemonResource("saw_entity")
|
||||
val LOST_ENTITY = cobblemonResource("lost_sight_of_entity")
|
||||
val HURT = cobblemonResource("hurt")
|
||||
val DIED = cobblemonResource("died")
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ import net.minecraft.world.level.material.FluidState
|
||||
interface OmniPathingEntity {
|
||||
fun canWalk(): Boolean
|
||||
fun canSwimInWater(): Boolean
|
||||
fun canWalkOnWater(): Boolean
|
||||
fun canSwimInLava(): Boolean
|
||||
fun canWalkOnLava(): Boolean
|
||||
fun canSwimUnderFluid(fluidState: FluidState): Boolean
|
||||
fun canFly(): Boolean
|
||||
fun isFlying(): Boolean
|
||||
|
||||
@@ -49,7 +49,7 @@ enum class PoseType {
|
||||
val UI_POSES = EnumSet.of(PROFILE, PORTRAIT)
|
||||
val MOVING_POSES = EnumSet.of(WALK, SWIM, FLY)
|
||||
val STATIONARY_POSES = EnumSet.of(STAND, FLOAT, HOVER)
|
||||
val NO_GRAV_POSES = EnumSet.of(FLY, HOVER, FLOAT, SWIM)
|
||||
val NO_GRAV_POSES = EnumSet.of(FLY, HOVER, SWIM)
|
||||
|
||||
fun identified() : List<ResourceLocation> {
|
||||
return ALL_POSES.stream()
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.ai
|
||||
|
||||
import com.cobblemon.mod.common.entity.OmniPathingEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.tags.FluidTags
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.util.GoalUtils
|
||||
import net.minecraft.world.entity.ai.util.RandomPos
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.*
|
||||
import java.util.function.Supplier
|
||||
import java.util.function.ToDoubleFunction
|
||||
|
||||
/*
|
||||
*
|
||||
* This is a rewrite of Minecraft's LandRandomPos tuned for
|
||||
* water and lava walkers.
|
||||
* The only real difference is movePosUpOutOfSolid() which
|
||||
* moves the target pos out of liquids
|
||||
*
|
||||
* */
|
||||
class CobblemonRandomSurfacePos {
|
||||
companion object {
|
||||
fun getPos(mob: PathfinderMob, radius: Int, verticalRange: Int): Vec3? {
|
||||
Objects.requireNonNull(mob)
|
||||
return getPos(
|
||||
mob,
|
||||
radius,
|
||||
verticalRange,
|
||||
{ pos: BlockPos? ->
|
||||
if (pos != null) {
|
||||
mob.getWalkTargetValue(pos).toDouble()
|
||||
}
|
||||
0.0
|
||||
})
|
||||
}
|
||||
|
||||
fun getPos(mob: PathfinderMob, radius: Int, yRange: Int, toDoubleFunction: ToDoubleFunction<BlockPos?>): Vec3? {
|
||||
val bl = GoalUtils.mobRestricted(mob, radius)
|
||||
return RandomPos.generateRandomPos(Supplier {
|
||||
val blockPos = RandomPos.generateRandomDirection(mob.getRandom(), radius, yRange)
|
||||
val blockPos2 = generateRandomPosTowardDirection(mob, radius, bl, blockPos)
|
||||
if (blockPos2 == null) null else movePosUpOutOfSolid(mob, blockPos2)
|
||||
}, toDoubleFunction)
|
||||
}
|
||||
|
||||
fun getPosTowards(mob: PathfinderMob, radius: Int, yRange: Int, vectorPosition: Vec3): Vec3? {
|
||||
val vec3 = vectorPosition.subtract(mob.getX(), mob.getY(), mob.getZ())
|
||||
val bl = GoalUtils.mobRestricted(mob, radius)
|
||||
return getPosInDirection(mob, radius, yRange, vec3, bl)
|
||||
}
|
||||
private fun getPosInDirection(
|
||||
mob: PathfinderMob,
|
||||
radius: Int,
|
||||
yRange: Int,
|
||||
vectorPosition: Vec3,
|
||||
shortCircuit: Boolean
|
||||
): Vec3? {
|
||||
return RandomPos.generateRandomPos(mob, Supplier {
|
||||
val blockPos: BlockPos? =
|
||||
RandomPos.generateRandomDirectionWithinRadians(
|
||||
mob.getRandom(),
|
||||
radius,
|
||||
yRange,
|
||||
0,
|
||||
vectorPosition.x,
|
||||
vectorPosition.z,
|
||||
(Math.PI.toFloat() / 2f).toDouble()
|
||||
)
|
||||
if (blockPos == null) {
|
||||
return@Supplier null
|
||||
} else {
|
||||
val blockPos2: BlockPos? =
|
||||
generateRandomPosTowardDirection(
|
||||
mob,
|
||||
radius,
|
||||
shortCircuit,
|
||||
blockPos
|
||||
)
|
||||
return@Supplier if (blockPos2 == null) null else movePosUpOutOfSolid(
|
||||
mob,
|
||||
blockPos2
|
||||
)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
fun generateRandomPosTowardDirection(
|
||||
mob: PathfinderMob,
|
||||
radius: Int,
|
||||
shortCircuit: Boolean,
|
||||
pos: BlockPos
|
||||
): BlockPos? {
|
||||
val blockPos = RandomPos.generateRandomPosTowardDirection(mob, radius, mob.getRandom(), pos)
|
||||
return if (!GoalUtils.isOutsideLimits(blockPos, mob) && !GoalUtils.isRestricted(
|
||||
shortCircuit,
|
||||
mob,
|
||||
blockPos
|
||||
) && !GoalUtils.isNotStable(mob.getNavigation(), blockPos)
|
||||
) blockPos else null
|
||||
}
|
||||
|
||||
fun movePosUpOutOfSolid(mob: PathfinderMob, pos: BlockPos): BlockPos? {
|
||||
var pos = pos
|
||||
pos = RandomPos.moveUpOutOfSolid(
|
||||
pos,
|
||||
mob.level().maxBuildHeight
|
||||
) { blockPos: BlockPos ->
|
||||
if (GoalUtils.isSolid(mob, blockPos)) true
|
||||
val fluidState = mob.level().getFluidState(blockPos)
|
||||
!fluidState.isEmpty && (mob !is OmniPathingEntity || ((mob.canWalkOnWater() && fluidState.type == FluidTags.WATER) || (mob.canWalkOnLava() && fluidState.type == FluidTags.LAVA)))
|
||||
}
|
||||
return if (!GoalUtils.hasMalus(mob, pos)) pos else null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,11 @@ import com.google.common.collect.ImmutableMap
|
||||
import java.util.UUID
|
||||
import kotlin.math.pow
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.MoverType
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
@@ -67,8 +69,14 @@ class FollowHerdLeaderTask : Behavior<PokemonEntity>(
|
||||
entity.brain.eraseMemory(CobblemonMemories.HERD_LEADER) // We can't go where this guy's going
|
||||
return
|
||||
}
|
||||
entity.setFlying(true)
|
||||
entity.addDeltaMovement(Vec3(0.0, 2.0, 0.0))
|
||||
entity.brain.setMemory(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
CobblemonWalkTarget(
|
||||
pos = leader.blockPosition(),
|
||||
speedModifier = 0.3F,
|
||||
completionRange = closeEnough.toInt()
|
||||
)
|
||||
)
|
||||
} else if (leaderMoveControl.banking) {
|
||||
if (leader.isInLiquid && !entity.isInLiquid) {
|
||||
// We should get into water asap so we can mimic the banking
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.entity.ai
|
||||
|
||||
import com.cobblemon.mod.common.entity.OmniPathingEntity
|
||||
import com.cobblemon.mod.common.pokemon.ai.OmniPathNodeMaker
|
||||
import com.cobblemon.mod.common.util.deleteNode
|
||||
import com.cobblemon.mod.common.util.getWaterAndLavaIn
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.google.common.collect.ImmutableSet
|
||||
@@ -27,7 +28,6 @@ import net.minecraft.world.level.pathfinder.Path
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.level.pathfinder.PathFinder
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.abs
|
||||
@@ -132,7 +132,7 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
|
||||
val f = abs(mob.z - targetVec3d.z)
|
||||
val closeEnough = d < maxDistanceToWaypoint.toDouble()
|
||||
&& f < this.maxDistanceToWaypoint.toDouble()
|
||||
&& e < (if (currentNode.type in verticallyPreciseNodeTypes) maxDistanceToWaypoint else 1.0).toDouble()
|
||||
&& e < (if (currentNode.type in verticallyPreciseNodeTypes && (mob.isUnderWater || pather.isFlying())) 1.0 else 1.0).toDouble()
|
||||
|
||||
// Corner cutting is commented out because it makes pokemon and NPCs 'cut' the corner and fall into water or lava
|
||||
if (closeEnough) {// || mob.navigation.canCutCorner(path!!.nextNode.type) && shouldTargetNextNodeInDirection(vec3d)) {
|
||||
@@ -228,6 +228,25 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (mob.canBreatheUnderwater()) {
|
||||
val blockGetter: BlockGetter = level
|
||||
if (blockGetter.getFluidState(pos).`is`(FluidTags.WATER)) {
|
||||
val blockPos = pos.below()
|
||||
return level.getBlockState(blockPos).isSolidRender(this.level, blockPos)
|
||||
}
|
||||
}
|
||||
if (pather.canWalkOnWater()) {
|
||||
val blockGetter: BlockGetter = level
|
||||
if (blockGetter.getFluidState(pos.below()).`is`(FluidTags.WATER)) {
|
||||
return !level.getBlockState(pos).isSolidRender(this.level, pos)
|
||||
}
|
||||
}
|
||||
if (pather.canWalkOnLava()) {
|
||||
val blockGetter: BlockGetter = level
|
||||
if (blockGetter.getFluidState(pos.below()).`is`(FluidTags.LAVA)) {
|
||||
return !level.getBlockState(pos).isSolidRender(this.level, pos)
|
||||
}
|
||||
}
|
||||
if (pather.canFly()) {
|
||||
return this.level.getBlockState(pos).isAir || super.isStableDestination(pos)
|
||||
// Note the below is what is used by default for minecraft fliers
|
||||
@@ -245,7 +264,7 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
|
||||
// If we can fly and we're airborne, return the current Y position
|
||||
return vec.y
|
||||
}
|
||||
return if ((canFloat()) && blockGetter.getFluidState(blockPos).`is`(FluidTags.WATER)) vec.y + 0.5 else WalkNodeEvaluator.getFloorLevel(blockGetter, blockPos)
|
||||
return if ((canFloat()) && blockGetter.getFluidState(blockPos).`is`(FluidTags.WATER)) vec.y + 0.5 else super.getGroundY(vec)
|
||||
}
|
||||
|
||||
override fun createPath(entity: Entity, distance: Int): Path? {
|
||||
@@ -269,6 +288,28 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
|
||||
override fun trimPath() {
|
||||
super.trimPath()
|
||||
val path = getPath() ?: return
|
||||
|
||||
// What's there to trim
|
||||
if (path.nodeCount < 2) {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
* Sometimes entities spin in place at the start of their path
|
||||
* because of rounding stuff (I think) so try to detect those
|
||||
* cases and nix the first node so they just move forward.
|
||||
*/
|
||||
val introNode = path.getNode(0)
|
||||
val subsequentNode = path.getNode(1)
|
||||
val mobMiddle = entity.position()
|
||||
val toIntroNode = introNode.asVec3().add(0.5, 0.0, 0.5).subtract(mobMiddle)
|
||||
val toSubsequentNode = subsequentNode.asVec3().add(0.5, 0.0, 0.5).subtract(mobMiddle)
|
||||
// if the first two nodes are pointing in opposite directions (>90 degrees) from the entity or the second node is closer, trim the first node
|
||||
if (toIntroNode.dot(toSubsequentNode) < 0 || toIntroNode.lengthSqr() > toSubsequentNode.lengthSqr()) {
|
||||
path.deleteNode(0)
|
||||
}
|
||||
|
||||
|
||||
var i = 2
|
||||
|
||||
// Tries to skip some nodes that are all lined up
|
||||
|
||||
@@ -20,7 +20,8 @@ class StayAfloatTask(private val chance: Float = 0F) : Behavior<PathfinderMob>(
|
||||
ImmutableMap.of(CobblemonMemories.POKEMON_BATTLE, MemoryStatus.VALUE_ABSENT) // Prevents Illusion Pokemon from bouncing in the water when disguised as swimmers.
|
||||
) {
|
||||
override fun checkExtraStartConditions(world: ServerLevel, entity: PathfinderMob): Boolean {
|
||||
return entity.isInWater && (entity.getFluidHeight(FluidTags.WATER) > entity.fluidJumpThreshold) || entity.isInLava
|
||||
return entity.isInWater && (entity.getFluidHeight(FluidTags.WATER) > entity.fluidJumpThreshold) ||
|
||||
(entity.isInLava && !entity.fireImmune())
|
||||
}
|
||||
|
||||
override fun canStillUse(world: ServerLevel, entity: PathfinderMob, l: Long): Boolean {
|
||||
|
||||
@@ -644,20 +644,6 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun hurt(source: DamageSource, amount: Float): Boolean {
|
||||
if (super.hurt(source, amount)) {
|
||||
callbacks.process(
|
||||
type = EntityCallbacks.HURT,
|
||||
functions = mapOf(
|
||||
"source" to { source.asMoLangValue() },
|
||||
"amount" to { DoubleValue(amount.toDouble()) },
|
||||
)
|
||||
)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun recalling(pokemonEntity: PokemonEntity): CompletableFuture<Unit> {
|
||||
playAnimation(RECALL_ANIMATION, pokemonExpressions(pokemonEntity.pokemon))
|
||||
return delayedFuture(seconds = 1.6F)
|
||||
@@ -710,10 +696,18 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canWalkOnLava(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canSwimUnderFluid(fluidState: FluidState): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canWalkOnWater(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canFly(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
package com.cobblemon.mod.common.entity.npc.ai
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
@@ -26,11 +24,9 @@ object MeleeAttackTask {
|
||||
fun create(range: Expression, cooldownTicks: Expression): OneShot<LivingEntity> = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.ATTACK_TARGET),
|
||||
it.absent(MemoryModuleType.ATTACK_COOLING_DOWN),
|
||||
it.absent(MemoryModuleType.ATTACK_COOLING_DOWN)
|
||||
).apply(it) { attackTarget, cooldown ->
|
||||
Trigger { world, entity, _ ->
|
||||
val attackTargetData = entity.brain.getMemorySafely(CobblemonMemories.ATTACK_TARGET_DATA).orElse(null)
|
||||
|
||||
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val range = mainThreadRuntime.resolveFloat(range)
|
||||
val cooldownTicks = mainThreadRuntime.resolveInt(cooldownTicks)
|
||||
@@ -39,14 +35,6 @@ object MeleeAttackTask {
|
||||
if (entity.distanceTo(attackTarget) <= range) {
|
||||
entity.doHurtTarget(attackTarget)
|
||||
cooldown.setWithExpiry(true, cooldownTicks.toLong())
|
||||
if (attackTargetData != null) {
|
||||
if (attackTargetData.dealtHitsUntilDisengage == 1) {
|
||||
attackTargetData.dealtHitsUntilDisengage = 0
|
||||
attackTargetData.disengageAction(entity)
|
||||
} else if (attackTargetData.dealtHitsUntilDisengage > 0){
|
||||
attackTargetData.dealtHitsUntilDisengage--
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addLivingEntityFuncti
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonEntityFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.net.serializers.PlatformTypeDataSerializer
|
||||
@@ -97,6 +96,7 @@ import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler.SEND_OUT_DURATION
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData
|
||||
@@ -124,6 +124,7 @@ import java.util.UUID
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.component.DataComponents
|
||||
@@ -175,6 +176,7 @@ import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LightLayer
|
||||
import net.minecraft.world.level.block.SuspiciousEffectHolder
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.level.material.EmptyFluid
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
@@ -1221,14 +1223,6 @@ open class PokemonEntity(
|
||||
// Only touch battle HP for non-wild Pokémon so that quick ball et. al. aren't owerpowered.
|
||||
pokemon.currentHealth = (pokemon.maxHealth * (this.health / this.maxHealth)).toInt()
|
||||
}
|
||||
|
||||
callbacks.process(
|
||||
type = EntityCallbacks.HURT,
|
||||
functions = mapOf(
|
||||
"source" to { source.asMoLangValue() },
|
||||
"amount" to { DoubleValue(amount.toDouble()) },
|
||||
)
|
||||
)
|
||||
true
|
||||
} else false
|
||||
}
|
||||
@@ -1804,7 +1798,7 @@ open class PokemonEntity(
|
||||
for (passenger in this.passengers) {
|
||||
passenger.deltaMovement = this.deltaMovement
|
||||
}
|
||||
this.ejectPassengers()
|
||||
DismountPokemonPacket().sendToServer()
|
||||
|
||||
// Reset ride velocity
|
||||
state.rideVelocity.set(state.rideVelocity.get().multiply(0.0, 1.0, 0.0))
|
||||
@@ -1871,6 +1865,13 @@ open class PokemonEntity(
|
||||
fun isFalling() =
|
||||
this.fallDistance > 0 && this.level().getBlockState(this.blockPosition().below()).isAir && !this.isFlying()
|
||||
|
||||
override fun checkFallDamage(y: Double, onGround: Boolean, state: BlockState, pos: BlockPos) {
|
||||
super.checkFallDamage(y, onGround, state, pos)
|
||||
if (isFlying() && this.passengers.isEmpty() && y < 0.0 && !onGround) {
|
||||
fallDistance = 0F // Prevent fall damage after flying without a rider
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCurrentPoseType(): PoseType = this.entityData.get(POSE_TYPE)
|
||||
|
||||
/**
|
||||
@@ -2043,10 +2044,6 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
override fun canBeLeashed() = true
|
||||
// override fun canBeLeashedBy(player: Player): Boolean {
|
||||
// return this.ownerUuid == null || this.ownerUuid == player.uuid
|
||||
// }
|
||||
|
||||
override fun setLeashedTo(entity: Entity, bl: Boolean) {
|
||||
super.setLeashedTo(entity, bl)
|
||||
if (this.ownerUUID != null && this.ownerUUID != entity.uuid) {
|
||||
@@ -2054,8 +2051,8 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
|
||||
/** Retrieves the battle theme associated with this Pokemon's Species/Form, or the default PVW theme if not found. */
|
||||
fun getBattleTheme() = this.form.battleTheme ?: CobblemonSounds.PVW_BATTLE.location
|
||||
/** Retrieves the battle theme associated with this Pokemon's Species/Form which falls back to the default PVW theme if not found. */
|
||||
fun getBattleTheme() = this.form.battleTheme
|
||||
|
||||
/**
|
||||
* A utility method to instance a [Pokemon] aware if the [world] is client sided or not.
|
||||
@@ -2069,22 +2066,23 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
// Takes in a requested stat type with a base minimum and base maximum and returns the interpolated
|
||||
// stat based on the boost of that pokemons stat
|
||||
fun getRideStat(stat: RidingStat, style: RidingStyle, baseMin: Double, baseMax: Double): Double {
|
||||
//TODO: Change from static zero boost once aprijuice is implemented.
|
||||
if (rideStatOverrides[style] != null && rideStatOverrides[style]!![stat] != null) {
|
||||
return (((baseMax - baseMin) / 100) * rideStatOverrides[style]!![stat]!!) + baseMin
|
||||
// stat based on the boost of that Pokémon's stat
|
||||
fun getRideStat(rideStat: RidingStat, style: RidingStyle, baseMin: Double, baseMax: Double): Double {
|
||||
if (rideStatOverrides[style] != null && rideStatOverrides[style]!![rideStat] != null) {
|
||||
return (((baseMax - baseMin) / 100) * rideStatOverrides[style]!![rideStat]!!) + baseMin
|
||||
}
|
||||
val stat = this.rideProp.behaviours?.get(style)?.calculate(stat, 0) ?: return 0.0
|
||||
val stat = this.rideProp.behaviours?.get(style)?.calculate(rideStat, entityData.get(RIDE_BOOSTS)[rideStat] ?: 0F) ?: return 0.0
|
||||
val statVal = (((baseMax - baseMin) / 100) * stat) + baseMin
|
||||
return statVal
|
||||
// Cap the minimum value at a very small value to prevent control inversions and other unexpected behaviour in
|
||||
// the ride controllers when using negative values
|
||||
return max(statVal, 1e-6)
|
||||
}
|
||||
|
||||
fun getRawRideStat(stat: RidingStat, style: RidingStyle): Double {
|
||||
if (rideStatOverrides[style] != null && rideStatOverrides[style]!![stat] != null) {
|
||||
return rideStatOverrides[style]!![stat]!!
|
||||
}
|
||||
return this.rideProp.behaviours?.get(style)?.calculate(stat, 0)?.toDouble() ?: 0.0
|
||||
return this.rideProp.behaviours?.get(style)?.calculate(stat, 0F)?.toDouble() ?: 0.0
|
||||
}
|
||||
|
||||
internal fun overrideRideStat(style: RidingStyle, stat: RidingStat, value: Double) {
|
||||
@@ -2398,8 +2396,10 @@ open class PokemonEntity(
|
||||
|
||||
override fun canWalk() = exposedForm.behaviour.moving.walk.canWalk
|
||||
override fun canSwimInWater() = exposedForm.behaviour.moving.swim.canSwimInWater
|
||||
override fun canWalkOnWater() = exposedForm.behaviour.moving.swim.canWalkOnWater
|
||||
override fun canFly() = exposedForm.behaviour.moving.fly.canFly
|
||||
override fun canSwimInLava() = exposedForm.behaviour.moving.swim.canSwimInLava
|
||||
override fun canWalkOnLava() = exposedForm.behaviour.moving.swim.canWalkOnLava
|
||||
override fun entityOnGround() = onGround()
|
||||
|
||||
override fun canSwimUnderFluid(fluidState: FluidState): Boolean {
|
||||
|
||||
+5
-3
@@ -76,12 +76,14 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
val moving = pokemon.form.behaviour.moving
|
||||
entity.setPathfindingMalus(PathType.LAVA, if (moving.swim.canSwimInLava) 12F else -1F)
|
||||
entity.setPathfindingMalus(PathType.WATER, if (moving.swim.canSwimInWater) 12F else -1F)
|
||||
entity.setPathfindingMalus(PathType.WATER_BORDER, if (moving.swim.canSwimInWater) 6F else -1F)
|
||||
entity.setPathfindingMalus(PathType.WATER_BORDER, if (moving.swim.canSwimInWater || moving.walk.avoidsLand || moving.swim.canBreatheUnderwater) 6F else -1F)
|
||||
if (moving.swim.canBreatheUnderwater) {
|
||||
entity.setPathfindingMalus(PathType.WATER, if (moving.walk.avoidsLand) 0F else 4F)
|
||||
// Must have a malus of zero to be a valid wander target
|
||||
entity.setPathfindingMalus(PathType.WATER, 0F)
|
||||
}
|
||||
if (moving.swim.canBreatheUnderlava) {
|
||||
entity.setPathfindingMalus(PathType.LAVA, if (moving.swim.canSwimInLava) 4F else -1F)
|
||||
// Must have a malus of zero to be a valid wander target
|
||||
entity.setPathfindingMalus(PathType.LAVA, if (moving.swim.canSwimInLava) 0F else -1F)
|
||||
}
|
||||
if (moving.walk.avoidsLand) {
|
||||
entity.setPathfindingMalus(PathType.WALKABLE, 12F)
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.item.components
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
data class HeldItemCapableComponent(val item: ResourceLocation) {
|
||||
companion object {
|
||||
val CODEC: Codec<HeldItemCapableComponent> = ResourceLocation.CODEC.xmap(
|
||||
{ HeldItemCapableComponent(it) },
|
||||
{ it.item }
|
||||
)
|
||||
|
||||
val PACKET_CODEC: StreamCodec<ByteBuf, HeldItemCapableComponent> = ByteBufCodecs.fromCodec(CODEC)
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.item.components
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
data class HeldItemEffectComponent(val showdownId: String, val consumed: Boolean = false) {
|
||||
companion object {
|
||||
val CODEC: Codec<HeldItemEffectComponent> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
Codec.STRING.fieldOf("showdownId").forGetter { it.showdownId },
|
||||
Codec.BOOL.fieldOf("consumed").forGetter { it.consumed },
|
||||
).apply(builder, ::HeldItemEffectComponent)
|
||||
}
|
||||
|
||||
val PACKET_CODEC: StreamCodec<ByteBuf, HeldItemEffectComponent> = ByteBufCodecs.fromCodec(CODEC)
|
||||
}
|
||||
|
||||
override fun toString(): String { return showdownId }
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is HeldItemEffectComponent
|
||||
&& this.showdownId == other.showdownId
|
||||
&& this.consumed == other.consumed
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = consumed.hashCode()
|
||||
result = 31 * result + showdownId.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.data
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
internal class UnlockReloadPacket : NetworkPacket<UnlockReloadPacket> {
|
||||
companion object {
|
||||
val ID = cobblemonResource("unlock_reload")
|
||||
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = UnlockReloadPacket()
|
||||
}
|
||||
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {}
|
||||
}
|
||||
+39
-26
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PlatformType
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -26,31 +27,32 @@ import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class SpawnPokemonPacket(
|
||||
var ownerId: UUID?,
|
||||
var pokemonUUID: UUID,
|
||||
var scaleModifier: Float,
|
||||
var speciesId: ResourceLocation,
|
||||
var gender: Gender,
|
||||
var shiny: Boolean,
|
||||
var formName: String,
|
||||
var aspects: Set<String>,
|
||||
var battleId: UUID?,
|
||||
var phasingTargetId: Int,
|
||||
var beamMode: Byte,
|
||||
var platform: PlatformType,
|
||||
var nickname: MutableComponent?,
|
||||
var mark: ResourceLocation?,
|
||||
var labelLevel: Int,
|
||||
var poseType: PoseType,
|
||||
var unbattlable: Boolean,
|
||||
var hideLabel: Boolean,
|
||||
var caughtBall: ResourceLocation,
|
||||
var spawnYaw: Float,
|
||||
var friendship: Int,
|
||||
var freezeFrame: Float,
|
||||
var passengers: IntArray,
|
||||
var tickSpawned: Int,
|
||||
vanillaSpawnPacket: ClientboundAddEntityPacket,
|
||||
var ownerId: UUID?,
|
||||
var pokemonUUID: UUID,
|
||||
var scaleModifier: Float,
|
||||
var speciesId: ResourceLocation,
|
||||
var gender: Gender,
|
||||
var shiny: Boolean,
|
||||
var formName: String,
|
||||
var aspects: Set<String>,
|
||||
var battleId: UUID?,
|
||||
var phasingTargetId: Int,
|
||||
var beamMode: Byte,
|
||||
var platform: PlatformType,
|
||||
var nickname: MutableComponent?,
|
||||
var mark: ResourceLocation?,
|
||||
var labelLevel: Int,
|
||||
var poseType: PoseType,
|
||||
var unbattlable: Boolean,
|
||||
var hideLabel: Boolean,
|
||||
var caughtBall: ResourceLocation,
|
||||
var spawnYaw: Float,
|
||||
var friendship: Int,
|
||||
var freezeFrame: Float,
|
||||
var passengers: IntArray,
|
||||
var tickSpawned: Int,
|
||||
var rideBoosts: Map<RidingStat, Float>,
|
||||
vanillaSpawnPacket: ClientboundAddEntityPacket,
|
||||
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
|
||||
|
||||
override val id: ResourceLocation = ID
|
||||
@@ -80,6 +82,7 @@ class SpawnPokemonPacket(
|
||||
entity.entityData.get(PokemonEntity.FREEZE_FRAME),
|
||||
entity.passengers.map { it.id }.toIntArray(),
|
||||
entity.tickCount,
|
||||
entity.entityData.get(PokemonEntity.RIDE_BOOSTS),
|
||||
vanillaSpawnPacket
|
||||
)
|
||||
|
||||
@@ -108,6 +111,11 @@ class SpawnPokemonPacket(
|
||||
buffer.writeFloat(this.freezeFrame)
|
||||
buffer.writeVarIntArray(this.passengers)
|
||||
buffer.writeInt(this.tickSpawned)
|
||||
buffer.writeMap(
|
||||
rideBoosts,
|
||||
{ _, stat -> buffer.writeEnumConstant(stat) },
|
||||
{ _, value -> buffer.writeFloat(value) }
|
||||
)
|
||||
}
|
||||
|
||||
override fun applyData(entity: PokemonEntity, level: ClientLevel) {
|
||||
@@ -137,6 +145,7 @@ class SpawnPokemonPacket(
|
||||
entity.entityData.set(PokemonEntity.SPAWN_DIRECTION, spawnYaw)
|
||||
entity.entityData.set(PokemonEntity.FRIENDSHIP, friendship)
|
||||
entity.entityData.set(PokemonEntity.FREEZE_FRAME, freezeFrame)
|
||||
entity.entityData.set(PokemonEntity.RIDE_BOOSTS, rideBoosts)
|
||||
|
||||
entity.ejectPassengers()
|
||||
passengers.forEach {
|
||||
@@ -176,9 +185,13 @@ class SpawnPokemonPacket(
|
||||
val freezeFrame = buffer.readFloat()
|
||||
val passengers = buffer.readVarIntArray()
|
||||
val tickSpawned = buffer.readInt()
|
||||
val rideBoosts = buffer.readMap(
|
||||
{ buffer.readEnumConstant(RidingStat::class.java) },
|
||||
{ buffer.readFloat() }
|
||||
)
|
||||
val vanillaPacket = decodeVanillaPacket(buffer)
|
||||
|
||||
return SpawnPokemonPacket(ownerId, pokemonUUID, scaleModifier, speciesId, gender, shiny, formName, aspects, battleId, phasingTargetId, beamModeEmitter, platform, nickname, mark, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, friendship, freezeFrame, passengers, tickSpawned, vanillaPacket)
|
||||
return SpawnPokemonPacket(ownerId, pokemonUUID, scaleModifier, speciesId, gender, shiny, formName, aspects, battleId, phasingTargetId, beamModeEmitter, platform, nickname, mark, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, friendship, freezeFrame, passengers, tickSpawned, rideBoosts, vanillaPacket)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.reactive.SettableObservable
|
||||
import com.cobblemon.mod.common.api.riding.RidingProperties
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
import com.cobblemon.mod.common.api.storage.StoreCoordinates
|
||||
@@ -1821,8 +1822,10 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
moveSet.update()
|
||||
}
|
||||
|
||||
fun getMaxRideBoost(stat: RidingStat): Int {
|
||||
return form.riding.behaviours?.maxOf { it.value.stats[stat]?.endInclusive ?: 0 } ?: 0
|
||||
fun getMaxRideBoost(stat: RidingStat): Float {
|
||||
val behaviours = form.riding.behaviours ?: return 0F
|
||||
// Get the widest range for this stat, max - min, since that's how far it can be boosted in theory.
|
||||
return behaviours.values.maxOfOrNull { it.stats[stat]?.let { it.last - it.first }?.toFloat() ?: 0F } ?: 0F
|
||||
}
|
||||
|
||||
fun getRideBoost(stat: RidingStat): Float {
|
||||
@@ -1833,31 +1836,36 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
return rideBoosts.toMap()
|
||||
}
|
||||
|
||||
fun canAddRideBoost(stat: RidingStat): Boolean {
|
||||
val max = getMaxRideBoost(stat)
|
||||
val current = rideBoosts[stat] ?: 0F
|
||||
return current < max
|
||||
fun getRideStat(style: RidingStyle, stat: RidingStat): Float {
|
||||
form.riding.behaviours?.let {
|
||||
return it[style]?.calculate(stat, getRideBoost(stat)) ?: 0F
|
||||
}
|
||||
return 0F
|
||||
}
|
||||
|
||||
fun addRideBoost(stat: RidingStat, boost: Float): Boolean {
|
||||
fun canAddRideBoost(stat: RidingStat): Boolean {
|
||||
val current = rideBoosts[stat] ?: 0F
|
||||
return current < getMaxRideBoost(stat)
|
||||
}
|
||||
|
||||
fun addRideBoost(stat: RidingStat, boostAmount: Float): Boolean {
|
||||
if (!canAddRideBoost(stat)) {
|
||||
return false
|
||||
}
|
||||
val max = getMaxRideBoost(stat)
|
||||
rideBoosts[stat] = (getRideBoost(stat) + boost).coerceIn(0F, max.toFloat())
|
||||
rideBoosts[stat] = (getRideBoost(stat) + boostAmount).coerceAtMost(max)
|
||||
onChange(RideBoostsUpdatePacket({ this }, rideBoosts))
|
||||
return true
|
||||
}
|
||||
|
||||
fun setRideBoost(stat: RidingStat, boost: Float) {
|
||||
val max = getMaxRideBoost(stat)
|
||||
rideBoosts[stat] = boost.coerceIn(0F, max.toFloat())
|
||||
rideBoosts[stat] = boost.coerceIn(0F, getMaxRideBoost(stat))
|
||||
onChange(RideBoostsUpdatePacket({ this }, rideBoosts))
|
||||
}
|
||||
|
||||
fun setRideBoosts(boosts: Map<RidingStat, Float>) {
|
||||
rideBoosts.clear()
|
||||
rideBoosts.putAll(boosts.mapValues { it.value.coerceIn(0F, getMaxRideBoost(it.key).toFloat()) })
|
||||
rideBoosts.putAll(boosts.mapValues { it.value.coerceIn(0F, getMaxRideBoost(it.key)) })
|
||||
onChange(RideBoostsUpdatePacket({ this }, rideBoosts))
|
||||
}
|
||||
|
||||
@@ -1877,7 +1885,7 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
if (result.experienceAdded <= 0) {
|
||||
return result
|
||||
}
|
||||
player.sendSystemMessage(lang("experience.gained", getDisplayName(), xp), true)
|
||||
player.sendSystemMessage(lang("experience.gained", getDisplayName(), result.experienceAdded), true)
|
||||
if (result.oldLevel != result.newLevel) {
|
||||
player.sendSystemMessage(lang("experience.level_up", getDisplayName(), result.newLevel))
|
||||
val repeats = result.newLevel - result.oldLevel
|
||||
|
||||
@@ -67,12 +67,12 @@ class FormPokemonBehaviour {
|
||||
val entityInteract: EntityBehaviour
|
||||
get() = _entityInteract ?: parent.entityInteract
|
||||
|
||||
val blockInteract: BlockBehavior
|
||||
get() = _blockInteract ?: parent.blockInteract
|
||||
|
||||
val dampensVibrations: Boolean
|
||||
get() = _dampensVibrations ?: parent.dampensVibrations
|
||||
|
||||
val blockInteract: BlockBehavior
|
||||
get() = _blockInteract ?: parent.blockInteract
|
||||
|
||||
val combat: CombatBehaviour
|
||||
get() = _combat ?: parent.combat
|
||||
|
||||
|
||||
@@ -35,6 +35,5 @@ class MoveBehaviour {
|
||||
it.addFunction("wander_chance") { DoubleValue(wanderChance) }
|
||||
it.addFunction("wander_speed") { DoubleValue(wanderSpeed) }
|
||||
it.addFunction("can_look") { DoubleValue(canLook) }
|
||||
it.addFunction("can_move") { DoubleValue(walk.canWalk || swim.canSwimInLava || swim.canSwimInWater || fly.canFly) }
|
||||
}
|
||||
}
|
||||
@@ -417,7 +417,11 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
PathType.FENCE
|
||||
}
|
||||
} else if (isWater && !canSwimInWater() && canBreatheUnderFluid && blockState.isPathfindable(PathComputationType.LAND) ) {
|
||||
PathType.OPEN
|
||||
if (pfContext.getPathTypeFromState(pos.x, pos.y - 1, pos.z) == PathType.BLOCKED) {
|
||||
PathType.WALKABLE
|
||||
} else {
|
||||
PathType.OPEN
|
||||
}
|
||||
} else if (isLava && canSwimInLava()) {
|
||||
PathType.LAVA
|
||||
} else if (isWater) {
|
||||
@@ -440,12 +444,13 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
|
||||
if (figuredNode == PathType.OPEN && pos.y >= pfContext.level().getMinBuildHeight() + 1) {
|
||||
val var10000: PathType = when (pfContext.getPathTypeFromState(pos.x, pos.y - 1, pos.z)) {
|
||||
PathType.OPEN, PathType.WATER, PathType.LAVA, PathType.WALKABLE -> PathType.OPEN
|
||||
PathType.OPEN, PathType.LAVA, PathType.WALKABLE -> PathType.OPEN
|
||||
PathType.DAMAGE_OTHER -> PathType.DAMAGE_OTHER
|
||||
PathType.STICKY_HONEY -> PathType.STICKY_HONEY
|
||||
PathType.POWDER_SNOW -> PathType.DANGER_POWDER_SNOW
|
||||
PathType.DAMAGE_CAUTIOUS -> PathType.DAMAGE_CAUTIOUS
|
||||
PathType.TRAPDOOR -> PathType.DANGER_TRAPDOOR
|
||||
PathType.WATER -> if (canWalkOnWater()) PathType.WALKABLE else PathType.OPEN
|
||||
PathType.FENCE -> {
|
||||
if (canFly())
|
||||
PathType.BLOCKED
|
||||
@@ -605,6 +610,14 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
}
|
||||
}
|
||||
|
||||
fun canWalkOnWater(): Boolean {
|
||||
return if (this.mob is OmniPathingEntity) {
|
||||
(this.mob as OmniPathingEntity).canWalkOnWater()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun canFly(): Boolean {
|
||||
return if (this.mob is OmniPathingEntity) {
|
||||
(this.mob as OmniPathingEntity).canFly()
|
||||
|
||||
+4
-10
@@ -10,9 +10,9 @@ package com.cobblemon.mod.common.pokemon.helditem
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.api.item.HeldItems
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemManager
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.google.common.collect.HashBiMap
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.network.chat.Component
|
||||
@@ -32,17 +32,11 @@ abstract class BaseCobblemonHeldItemManager : HeldItemManager {
|
||||
|
||||
internal open fun load() {
|
||||
this.itemIds.clear()
|
||||
val itemsJson = ShowdownService.service.getRegistryData("heldItem")
|
||||
val showdownIds = hashSetOf<String>()
|
||||
for (i in 0 until itemsJson.size()) {
|
||||
val jsItem = itemsJson[i].asJsonObject
|
||||
showdownIds += jsItem.get("id").asString
|
||||
}
|
||||
BuiltInRegistries.ITEM.forEach { item ->
|
||||
val identifier = BuiltInRegistries.ITEM.getKey(item)
|
||||
if (identifier.namespace == Cobblemon.MODID) {
|
||||
val formattedPath = identifier.path.replace("_", "")
|
||||
if (showdownIds.contains(formattedPath)) {
|
||||
if (HeldItems.showdownItems.contains(formattedPath)) {
|
||||
this.itemIds[formattedPath] = item
|
||||
}
|
||||
}
|
||||
@@ -51,9 +45,9 @@ abstract class BaseCobblemonHeldItemManager : HeldItemManager {
|
||||
|
||||
override fun showdownId(pokemon: BattlePokemon): String? {
|
||||
val item = pokemon.effectedPokemon.heldItemNoCopy()
|
||||
val identifier = item.get(CobblemonItemComponents.HELD_ITEM_REP)?.item ?: BuiltInRegistries.ITEM.getKey(item.item)
|
||||
val identifier = item.get(CobblemonItemComponents.HELD_ITEM_EFFECT)?.showdownId ?: BuiltInRegistries.ITEM.getKey(item.item).path
|
||||
|
||||
val formattedPath = identifier.path.replace("_", "")
|
||||
val formattedPath = identifier.replace("_", "")
|
||||
if (this.itemIds.containsKey(formattedPath)) {
|
||||
return formattedPath
|
||||
}
|
||||
|
||||
+16
-5
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.pokemon.helditem
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents.HELD_ITEM_EFFECT
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemManager
|
||||
@@ -60,9 +61,12 @@ object CobblemonHeldItemManager : BaseCobblemonHeldItemManager() {
|
||||
|
||||
override fun showdownId(pokemon: BattlePokemon): String? {
|
||||
val itemStack = pokemon.effectedPokemon.heldItemNoCopy()
|
||||
if (remaps.containsKey(itemStack.item)) {
|
||||
|
||||
if (itemStack.has(HELD_ITEM_EFFECT))
|
||||
return itemStack.get(HELD_ITEM_EFFECT)!!.showdownId
|
||||
|
||||
if (remaps.containsKey(itemStack.item))
|
||||
return remaps[itemStack.item]
|
||||
}
|
||||
|
||||
for (remap in stackRemaps) {
|
||||
val id = remap.apply(itemStack)
|
||||
@@ -80,9 +84,11 @@ object CobblemonHeldItemManager : BaseCobblemonHeldItemManager() {
|
||||
}
|
||||
|
||||
fun showdownId(itemStack: ItemStack): String? {
|
||||
if (remaps.containsKey(itemStack.item)) {
|
||||
if (itemStack.has(HELD_ITEM_EFFECT))
|
||||
return itemStack.get(HELD_ITEM_EFFECT)?.showdownId
|
||||
|
||||
if (remaps.containsKey(itemStack.item))
|
||||
return remaps[itemStack.item]
|
||||
}
|
||||
|
||||
for (remap in stackRemaps) {
|
||||
val id = remap.apply(itemStack)
|
||||
@@ -173,13 +179,18 @@ object CobblemonHeldItemManager : BaseCobblemonHeldItemManager() {
|
||||
}
|
||||
|
||||
override fun shouldConsumeItem(pokemon: BattlePokemon, battle: PokemonBattle, showdownId: String): Boolean {
|
||||
val itemStack = pokemon.effectedPokemon.heldItem()
|
||||
|
||||
if (itemStack.has(HELD_ITEM_EFFECT))
|
||||
return itemStack.get(HELD_ITEM_EFFECT)!!.consumed
|
||||
|
||||
// In 3rd party and the future battles might have multiple types, give it a priority from pvp down to wild.
|
||||
val tag = when {
|
||||
battle.isPvP -> CobblemonItemTags.CONSUMED_IN_PVP_BATTLE
|
||||
battle.isPvN -> CobblemonItemTags.CONSUMED_IN_NPC_BATTLE
|
||||
else -> CobblemonItemTags.CONSUMED_IN_WILD_BATTLE
|
||||
}
|
||||
return pokemon.effectedPokemon.heldItem().`is`(tag)
|
||||
return itemStack.`is`(tag)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"format_version": "1.8.0",
|
||||
"animations": {
|
||||
"animation.player.test_riding_pose": {
|
||||
"loop": "hold_on_last_frame",
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [22.5, 0, 0],
|
||||
"position": [0, 6, 0]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [-145.18392, -14.90835, "-20.3017894552"]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": [47.48933, -18.97397, 16.56855]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [-145.18392, -14.90835, 20.30179]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": [48.65802, 13.31791, -11.45696]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.player.default_ride_pose": {
|
||||
"loop": "hold_on_last_frame",
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, -10, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["v.head_pitch", "v.head_yaw", 0]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [-40, 0, 0]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [-40, 0, 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": [-81, 18, 4.5]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": [-81, -18, -4.5]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -5,9 +5,10 @@
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, -9, 0]
|
||||
"position": [0, -9, 0],
|
||||
"rotation": [25, 0, 0]
|
||||
},
|
||||
"torso": {
|
||||
"_torso_disabled_because_it_cannot_be_reparented": {
|
||||
"rotation": [25, 0, 0]
|
||||
},
|
||||
"arm_right": {
|
||||
|
||||
+699
-79
@@ -1,79 +1,15 @@
|
||||
{
|
||||
"format_version": "1.8.0",
|
||||
"animations": {
|
||||
"animation.dewgong.pose": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [0, 12.5, 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [2.41492, 0.64686, -14.98637]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [34.97911, 1.05627, -2.26603]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": [46.78082, -13.99545, -14.43276]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": [30, 0, 0]
|
||||
},
|
||||
"chest": {
|
||||
"rotation": [-32.5, 0, 0]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": [-52.52635, -1.5216, 1.98385]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [83.46987, -8.35694, -6.53013],
|
||||
"position": [0.58854, -0.68263, -0.01172]
|
||||
},
|
||||
"flipper_left": {
|
||||
"rotation": [32.28184, -14.8934, 25.70507],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_left2": {
|
||||
"rotation": [0, -15, -15]
|
||||
},
|
||||
"flipper_left3": {
|
||||
"rotation": [0, 0, -37.5]
|
||||
},
|
||||
"flipper_right": {
|
||||
"rotation": [99.40658, 28.75123, -7.23212],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_right2": {
|
||||
"rotation": [0, 0, 15]
|
||||
},
|
||||
"flipper_right3": {
|
||||
"rotation": [0, 0, 37.5]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": [27.5, 0, 0]
|
||||
},
|
||||
"eye_right": {
|
||||
"position": [0.25, 0, 0]
|
||||
},
|
||||
"eye_highlight_left": {
|
||||
"position": [0.25, 0, 0]
|
||||
},
|
||||
"eye_highlight_right": {
|
||||
"position": [0.25, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.ground_idle": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [-5, 0, 0]
|
||||
"rotation": ["-5+Math.cos((query.anim_time) * 90 * 2) * 1", 0, 0],
|
||||
"position": [0, 0, "0+Math.cos((query.anim_time) * 90 * 2) * -0.3"]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
"rotation": ["-2.5+Math.cos((query.anim_time) * 90 * 2) * -1", 0, 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [0, 0, 0]
|
||||
@@ -88,16 +24,16 @@
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"chest": {
|
||||
"rotation": [-32.5, 0, 0]
|
||||
"rotation": ["-32.5+Math.cos((query.anim_time) * 90 * 2 - 45) * 0.5", 0, 0]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": [-50, 0, 0]
|
||||
"rotation": ["-50+Math.cos((query.anim_time) * 90 * 2) * -1", 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [85, 0, 0]
|
||||
"rotation": ["85+Math.cos((query.anim_time) * 90 * 2 + 45) * 1", 0, 0]
|
||||
},
|
||||
"flipper_left": {
|
||||
"rotation": [25.90134, -21.60983, 48.92416],
|
||||
"rotation": [25.90134, -21.60983, "51.4242+Math.cos((query.anim_time) * 90 * 2) * -1"],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_left2": {
|
||||
@@ -107,7 +43,7 @@
|
||||
"rotation": [0, 0, -37.5]
|
||||
},
|
||||
"flipper_right": {
|
||||
"rotation": [25.90134, 21.60983, -48.92416],
|
||||
"rotation": [25.90134, 21.60983, "-51.4242+Math.cos((query.anim_time) * 90 * 2) * 1"],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_right2": {
|
||||
@@ -117,7 +53,507 @@
|
||||
"rotation": [0, 0, 37.5]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [5, 0, 0]
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 2) * -0.5", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.ground_walk": {
|
||||
"loop": true,
|
||||
"animation_length": 1,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": {
|
||||
"0.0": [-5, 0, 0],
|
||||
"0.1667": [-0.495, 0, 0],
|
||||
"0.25": [0, 0, 0],
|
||||
"0.3333": [-0.5, 0, 0],
|
||||
"0.5": [-4.795, 0, 0],
|
||||
"0.5417": [-5.4, 0, 0],
|
||||
"0.6667": [-5, 0, 0]
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0, 0, "0+Math.cos((query.anim_time) * 90 * 4) * 3"],
|
||||
"0.0833": [0, 0, "0+Math.cos((query.anim_time) * 90 * 4) * 3"],
|
||||
"0.2083": [0, 1.36, "0+Math.cos((query.anim_time) * 90 * 4) * 3"],
|
||||
"0.2917": [0, 1.845, "0+Math.cos((query.anim_time) * 90 * 4) * 3"],
|
||||
"0.3333": [0, 2, "0+Math.cos((query.anim_time) * 90 * 4) * 3"],
|
||||
"0.375": [0, 1.845, "0+Math.cos((query.anim_time) * 90 * 4) * 3"],
|
||||
"0.4583": [0, 1.36, "0+Math.cos((query.anim_time) * 90 * 4) * 3"],
|
||||
"0.5833": [0, 0, "0+Math.cos((query.anim_time) * 90 * 4) * 3"]
|
||||
}
|
||||
},
|
||||
"tail": {
|
||||
"rotation": {
|
||||
"0.0": [5.775, 0, 0],
|
||||
"0.1667": [-13.44, 0, 0],
|
||||
"0.2083": [-15, 0, 0],
|
||||
"0.5": [0, 0, 0],
|
||||
"0.875": [7.5, 0, 0],
|
||||
"1.0": [5.775, 0, 0]
|
||||
}
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": {
|
||||
"0.0": [15, 0, 0],
|
||||
"0.1667": [0, 0, 0],
|
||||
"0.5417": [0, 0, 0],
|
||||
"0.6667": [-7.5, 0, 0],
|
||||
"0.8333": [12.46, 0, 0],
|
||||
"0.9167": [17.42, 0, 0],
|
||||
"1.0": [15, 0, 0]
|
||||
}
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": {
|
||||
"0.0": [22.5, 0, 0],
|
||||
"0.125": [34.5, 0, 0],
|
||||
"0.2083": [17.5, 0, 0],
|
||||
"0.3333": [-5, 0, 0],
|
||||
"0.5417": [-5, 0, 0],
|
||||
"0.6667": [0, 0, 0],
|
||||
"0.75": [-22.5, 0, 0],
|
||||
"1.0": [22.5, 0, 0]
|
||||
}
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": {
|
||||
"0.0": [25, 0, 0],
|
||||
"0.125": [17.5, 0, 0],
|
||||
"0.25": [-5.45, 0, 0],
|
||||
"0.2917": [2.5, 0, 0],
|
||||
"0.7083": [2.5, 0, 0],
|
||||
"0.75": [-1.67, 0, 0],
|
||||
"0.8333": [-25, 0, 0],
|
||||
"1.0": [25, 0, 0]
|
||||
}
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": {
|
||||
"0.0": [-42.5, 0, 0],
|
||||
"0.1667": [44.17, 0, 0],
|
||||
"0.25": [42.5, 0, 0],
|
||||
"0.2917": [2.5, 0, 0],
|
||||
"0.3333": [2.5, 0, 0],
|
||||
"0.75": [2.5, 0, 0],
|
||||
"0.7917": [20, 0, 0],
|
||||
"0.8333": [40, 0, 0],
|
||||
"0.875": [-40, 0, 0],
|
||||
"1.0": [-42.5, 0, 0]
|
||||
}
|
||||
},
|
||||
"chest": {
|
||||
"rotation": {
|
||||
"0.0": [-32.5, 0, 0],
|
||||
"0.0833": {
|
||||
"pre": [-26.79, 0, 0],
|
||||
"post": [-26.79, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.1667": {
|
||||
"post": [-22, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.3333": {
|
||||
"post": [-18.575, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.5": {
|
||||
"post": [-17.5, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.5833": {
|
||||
"post": [-21.6, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.6667": {
|
||||
"post": [-29.47, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.7083": {
|
||||
"post": [-33.695, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.7917": {
|
||||
"post": [-38, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.875": {
|
||||
"post": [-36.9, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.0": [-32.5, 0, 0]
|
||||
}
|
||||
},
|
||||
"neck": {
|
||||
"rotation": {
|
||||
"0.0": [-50, 0, 0],
|
||||
"0.1667": [-40, 0, 0],
|
||||
"0.2917": [-37.575, 0, 0],
|
||||
"0.5833": [-36.815, 0, 0],
|
||||
"0.7083": [-39.345, 0, 0],
|
||||
"0.8333": [-47.315, 0, 0],
|
||||
"0.9167": [-49.585, 0, 0],
|
||||
"1.0": [-50, 0, 0]
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.1667": [0, 0, 1],
|
||||
"0.6667": [0, 0, 1],
|
||||
"1.0": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": {
|
||||
"0.0": [85, 0, 0],
|
||||
"0.1667": [62, 0, 0],
|
||||
"0.2083": [60, 0, 0],
|
||||
"0.4167": [55, 0, 0],
|
||||
"0.5417": [57, 0, 0],
|
||||
"0.7917": [79.5, 0, 0],
|
||||
"0.9167": [84.175, 0, 0],
|
||||
"1.0": [85, 0, 0]
|
||||
}
|
||||
},
|
||||
"flipper_left": {
|
||||
"rotation": {
|
||||
"0.0": [70.90134, 0.89017, 78.92416],
|
||||
"0.25": [17.15, -1.36, 58.92],
|
||||
"0.2917": [13.11, -5.57, 54.92],
|
||||
"0.4583": [-3.06, -22.4, 43.92],
|
||||
"0.5": [-9.1, -26.61, 43.92],
|
||||
"0.625": [16.53, -12.375, 38.315],
|
||||
"0.6667": [22.57, -3.065, 36.275],
|
||||
"0.75": [34.65, 4.64, 35.195],
|
||||
"0.9167": [58.82, 6.785, 50.56],
|
||||
"1.0": [70.90134, 0.89017, 78.92416]
|
||||
},
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_left2": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, -42.5],
|
||||
"0.0417": [0, 0, -26.875],
|
||||
"0.0833": [0, 0, -40],
|
||||
"0.125": [0, 0, -48.13],
|
||||
"0.1667": [0, 0, -51.25],
|
||||
"0.25": [0, 0, -42.5],
|
||||
"0.375": [0, 0, -29.25],
|
||||
"0.5": [0, 0, -20],
|
||||
"0.5417": [0, 0, -18.75],
|
||||
"0.5833": [0, 0, -32.5],
|
||||
"0.7917": [0, 0, -42.5],
|
||||
"1.0": [0, 0, -42.5]
|
||||
}
|
||||
},
|
||||
"flipper_left3": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, -70],
|
||||
"0.0833": [0, 0, -22.5],
|
||||
"0.1667": [0, 0, -11.67],
|
||||
"0.2083": [0, 0, -16.25],
|
||||
"0.5": [0, 0, -25],
|
||||
"0.5417": [0, 0, -25.83],
|
||||
"0.625": [0, 0, 20],
|
||||
"0.7917": [0, 0, -47.5],
|
||||
"1.0": [0, 0, -70]
|
||||
}
|
||||
},
|
||||
"flipper_right": {
|
||||
"rotation": {
|
||||
"0.0": [70.90134, -0.89017, -78.92416],
|
||||
"0.25": [17.15, 1.36, -58.92],
|
||||
"0.2917": [13.11, 5.57, -54.92],
|
||||
"0.4583": [-3.06, 22.4, -43.92],
|
||||
"0.5": [-9.1, 26.61, -43.92],
|
||||
"0.625": [16.53, 12.375, -38.315],
|
||||
"0.6667": [22.57, 3.065, -36.275],
|
||||
"0.75": [34.65, -4.64, -35.195],
|
||||
"0.9167": [58.82, -6.785, -50.56],
|
||||
"1.0": [70.90134, -0.89017, -78.92416]
|
||||
},
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_right2": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 42.5],
|
||||
"0.0417": [0, 0, 26.875],
|
||||
"0.0833": [0, 0, 40],
|
||||
"0.125": [0, 0, 48.13],
|
||||
"0.1667": [0, 0, 51.25],
|
||||
"0.25": [0, 0, 42.5],
|
||||
"0.375": [0, 0, 29.25],
|
||||
"0.5": [0, 0, 20],
|
||||
"0.5417": [0, 0, 18.75],
|
||||
"0.5833": [0, 0, 32.5],
|
||||
"0.7917": [0, 0, 42.5],
|
||||
"1.0": [0, 0, 42.5]
|
||||
}
|
||||
},
|
||||
"flipper_right3": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 70],
|
||||
"0.0833": [0, 0, 22.5],
|
||||
"0.1667": [0, 0, 11.67],
|
||||
"0.2083": [0, 0, 16.25],
|
||||
"0.5": [0, 0, 25],
|
||||
"0.5417": [0, 0, 25.83],
|
||||
"0.625": [0, 0, -20],
|
||||
"0.7917": [0, 0, 47.5],
|
||||
"1.0": [0, 0, 70]
|
||||
}
|
||||
},
|
||||
"torso": {
|
||||
"rotation": {
|
||||
"0.0": [4.6, 0, 0],
|
||||
"0.0417": [6.03, 0, 0],
|
||||
"0.125": [8.44, 0, 0],
|
||||
"0.2917": {
|
||||
"pre": [9.6, 0, 0],
|
||||
"post": [9.6, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.5833": {
|
||||
"post": [8.35, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.7917": {
|
||||
"post": [-1.9, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.9583": [3.13, 0, 0],
|
||||
"1.0": [4.6, 0, 0]
|
||||
}
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": {
|
||||
"0.0": [-6.95, 0, 0],
|
||||
"0.0833": [23.83, 0, 0],
|
||||
"0.2083": [32.5, 0, 0],
|
||||
"0.2917": [0, 0, 0],
|
||||
"0.3333": [7.5, 0, 0],
|
||||
"0.5417": [5, 0, 0],
|
||||
"0.6667": [5, 0, 0],
|
||||
"0.7083": [10, 0, 0],
|
||||
"0.75": [22.5, 0, 0],
|
||||
"0.7917": [1.25, 0, 0],
|
||||
"0.8333": [-22.5, 0, 0],
|
||||
"1.0": [-6.95, 0, 0]
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
"rotation": {
|
||||
"0.0833": [0, 0, 0],
|
||||
"0.2083": [25.75, 0, 0],
|
||||
"0.2917": [32.24, 0, 0],
|
||||
"0.4583": [32.5, 0, 0],
|
||||
"0.7083": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.water_idle": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": ["-5+Math.cos((query.anim_time) * 90 * 2 - 90) * -1", 0, 0],
|
||||
"position": [0, "0+Math.cos((query.anim_time) * 90 * 2) * 1", 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": ["-2.5+Math.cos((query.anim_time) * 90 * 2 - 150) * 2", 0, 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": ["-5+Math.cos((query.anim_time) * 90 * 2 - 210) * 2", 0, 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 2 - 270) * 3", 0, 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 2 - 300) * 3", 0, 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 2 - 450) * 12", 0, 0]
|
||||
},
|
||||
"chest": {
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 2 - 150) * -1", 0, 0],
|
||||
"position": [0, 0, 0.25]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": ["-50+Math.cos((query.anim_time) * 90 * 2 - 90) * 1", 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["52.5+Math.cos((query.anim_time) * 90 * 2 - 90) * 1", 0, 0],
|
||||
"position": [0, 0, 1]
|
||||
},
|
||||
"flipper_left": {
|
||||
"rotation": [0, -12.5, "12.5+Math.cos((query.anim_time) * 90 * 2 - 90) * -4"],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_left2": {
|
||||
"rotation": [0, 0, "10+Math.cos((query.anim_time) * 90 * 2 - 150) * -7"]
|
||||
},
|
||||
"flipper_left3": {
|
||||
"rotation": [0, 0, "10+Math.cos((query.anim_time) * 90 * 2 - 210) * -7"]
|
||||
},
|
||||
"flipper_right": {
|
||||
"rotation": [0, 12.5, "-12.5+Math.cos((query.anim_time) * 90 * 2 - 90) * 4"],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_right2": {
|
||||
"rotation": [0, 0, "-10+Math.cos((query.anim_time) * 90 * 2 - 150) * 7"]
|
||||
},
|
||||
"flipper_right3": {
|
||||
"rotation": [0, 0, "-10+Math.cos((query.anim_time) * 90 * 2 - 210) * 7"]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [2.5, 0, 0]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": ["7.5+Math.cos((query.anim_time) * 90 * 2 - 390) * 8", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.water_swim": {
|
||||
"loop": true,
|
||||
"animation_length": 0.75,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": ["-5+Math.cos((query.anim_time) * 90 * 16/3 - 45) * 2", 0, 0],
|
||||
"position": [0, "0+Math.cos((query.anim_time) * 90 * 16/3 + 45) * 2", "0+Math.cos((query.anim_time) * 90 * 16/3) * 3"]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": ["-2.5+Math.cos((query.anim_time) * 90 * 16/3 - 90) * 6", 0, 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": ["-5+Math.cos((query.anim_time) * 90 * 16/3 - 135) * 6", 0, 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 16/3 - 180) * 6", 0, 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 16/3 - 200) * 16", 0, 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 16/3 - 350) * 26", 0, 0]
|
||||
},
|
||||
"chest": {
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 16/3 + 45) * 1", 0, 0],
|
||||
"position": [0, 0, 0.25]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": ["-50+Math.cos((query.anim_time) * 90 * 16/3 + 90) * -2", 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["47.5+Math.cos((query.anim_time) * 90 * 16/3 - 45) * -6", 0, 0],
|
||||
"position": [0, 0, 1]
|
||||
},
|
||||
"flipper_left": {
|
||||
"rotation": {
|
||||
"0.0": [37.25, 50.65, 0],
|
||||
"0.0417": [37.25, 46.72, 1.1],
|
||||
"0.375": [37.25, -45.255, 12.5],
|
||||
"0.4167": [37.25, -47.5, 12.5],
|
||||
"0.4583": [39.9, -45.255, 12.5],
|
||||
"0.5417": [52.825, -13.75, 8.97],
|
||||
"0.5833": [55.5, -0.315, 7.2],
|
||||
"0.625": [52.325, 16.325, 5.03],
|
||||
"0.7083": [38.4, 46.72, 0.7],
|
||||
"0.75": [37.25, 50.65, 0]
|
||||
},
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_left2": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.125": [0, 0, -10],
|
||||
"0.2917": [0, 0, -0.76],
|
||||
"0.4167": [0, 0, 24.75],
|
||||
"0.4583": [0, 0, 37.5],
|
||||
"0.625": [0, 0, 64.5],
|
||||
"0.75": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"flipper_left3": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 10],
|
||||
"0.125": [0, 0, -7.5],
|
||||
"0.375": [0, 0, -9.37],
|
||||
"0.4583": [0, 0, 20],
|
||||
"0.625": [0, 0, 35],
|
||||
"0.75": [0, 0, 10]
|
||||
}
|
||||
},
|
||||
"flipper_right": {
|
||||
"rotation": {
|
||||
"0.0": [37.25, -50.65, 0],
|
||||
"0.0417": [37.25, -46.72, -1.1],
|
||||
"0.375": [37.25, 45.255, -12.5],
|
||||
"0.4167": [37.25, 47.5, -12.5],
|
||||
"0.4583": [39.9, 45.255, -12.5],
|
||||
"0.5417": [52.825, 13.75, -8.97],
|
||||
"0.5833": [55.5, 0.315, -7.2],
|
||||
"0.625": [52.325, -16.325, -5.03],
|
||||
"0.7083": [38.4, -46.72, -0.7],
|
||||
"0.75": [37.25, -50.65, 0]
|
||||
},
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_right2": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.125": [0, 0, 10],
|
||||
"0.2917": [0, 0, 0.76],
|
||||
"0.4167": [0, 0, -24.75],
|
||||
"0.4583": [0, 0, -37.5],
|
||||
"0.625": [0, 0, -64.5],
|
||||
"0.75": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"flipper_right3": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, -30],
|
||||
"0.0833": [0, 0, -3.17],
|
||||
"0.125": [0, 0, 7.5],
|
||||
"0.375": [0, 0, 9.37],
|
||||
"0.4583": [0, 0, -20],
|
||||
"0.625": [0, 0, -35],
|
||||
"0.75": [0, 0, -30]
|
||||
}
|
||||
},
|
||||
"torso": {
|
||||
"rotation": ["2.5+Math.cos((query.anim_time) * 90 * 16/3 + 0) * 2", 0, 0]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": ["7.5+Math.cos((query.anim_time) * 90 * 16/3 - 260) * 26", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.ride_water_swim": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [0, 0, "q.r.yaw_change(0)*-10"]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": ["q.r.pitch_change(0)*5", "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": ["q.r.pitch_change(4)*8", "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": ["q.r.pitch_change(6)*12", "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": ["q.r.pitch_change(0)*-5", "q.r.yaw_change(0)*5", 0]
|
||||
},
|
||||
"chest": {
|
||||
"rotation": ["q.r.pitch_change(0)*-10", "q.r.yaw_change(0)*5", 0],
|
||||
"position": [0, 0, "2+q.r.pitch_change(0)*-2"]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": ["q.r.pitch_change(0)*-5", "q.r.yaw_change(0)*5", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["q.r.pitch_change(0)*-20", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -140,11 +576,6 @@
|
||||
"1.25": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.dewgong.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.blink": {
|
||||
@@ -210,7 +641,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.new": {
|
||||
"animation.dewgong.neckdemo": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"neck": {
|
||||
@@ -220,6 +651,195 @@
|
||||
"rotation": [72.5, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.pose": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [0, 12.5, 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [2.41492, 0.64686, -14.98637]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [34.97911, 1.05627, -2.26603]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": [46.78082, -13.99545, -14.43276]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": [30, 0, 0]
|
||||
},
|
||||
"chest": {
|
||||
"rotation": [-32.5, 0, 0]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": [-52.52635, -1.5216, 1.98385]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [83.46987, -8.35694, -6.53013],
|
||||
"position": [0.58854, -0.68263, -0.01172]
|
||||
},
|
||||
"flipper_left": {
|
||||
"rotation": [32.28184, -14.8934, 25.70507],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_left2": {
|
||||
"rotation": [0, -15, -15]
|
||||
},
|
||||
"flipper_left3": {
|
||||
"rotation": [0, 0, -37.5]
|
||||
},
|
||||
"flipper_right": {
|
||||
"rotation": [99.40658, 28.75123, -7.23212],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_right2": {
|
||||
"rotation": [0, 0, 15]
|
||||
},
|
||||
"flipper_right3": {
|
||||
"rotation": [0, 0, 37.5]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": [27.5, 0, 0]
|
||||
},
|
||||
"eye_right": {
|
||||
"position": [0.25, 0, 0]
|
||||
},
|
||||
"eye_highlight_left": {
|
||||
"position": [0.25, 0, 0]
|
||||
},
|
||||
"eye_highlight_right": {
|
||||
"position": [0.25, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.test_walkspeed": {
|
||||
"loop": true,
|
||||
"animation_length": 3.5,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, 0, "39-q.anim_time*90*0.26"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.basepose": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [-5, 0, 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [0, 0, 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": [4.5, 0, 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"chest": {
|
||||
"rotation": [-32.5, 0, 0]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": [-50, 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [85, 0, 0]
|
||||
},
|
||||
"flipper_left": {
|
||||
"rotation": [25.90134, -21.60983, 48.92416],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_left2": {
|
||||
"rotation": [0, 0, -15]
|
||||
},
|
||||
"flipper_left3": {
|
||||
"rotation": [0, 0, -37.5]
|
||||
},
|
||||
"flipper_right": {
|
||||
"rotation": [25.90134, 21.60983, -48.92416],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_right2": {
|
||||
"rotation": [0, 0, 15]
|
||||
},
|
||||
"flipper_right3": {
|
||||
"rotation": [0, 0, 37.5]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [5, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dewgong.basepose_water": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [-5, 0, 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [-5, 0, 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"chest": {
|
||||
"rotation": [5, 0, 0],
|
||||
"position": [0, 0, 0.25]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": [-50, 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [52.5, 0, 0],
|
||||
"position": [0, 0, 1]
|
||||
},
|
||||
"flipper_left": {
|
||||
"rotation": [0, -12.5, 12.5],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_left2": {
|
||||
"rotation": [0, 0, 10]
|
||||
},
|
||||
"flipper_left3": {
|
||||
"rotation": [0, 0, 10]
|
||||
},
|
||||
"flipper_right": {
|
||||
"rotation": [0, 12.5, -12.5],
|
||||
"position": [0, -1.68678, 1.0746]
|
||||
},
|
||||
"flipper_right2": {
|
||||
"rotation": [0, 0, -10]
|
||||
},
|
||||
"flipper_right3": {
|
||||
"rotation": [0, 0, -10]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [2.5, 0, 0]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4781
-39
File diff suppressed because it is too large
Load Diff
+3581
-76
File diff suppressed because it is too large
Load Diff
+274
-117
@@ -40,19 +40,19 @@
|
||||
"tail_right5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9+120)*10", "-math.sin(q.anim_time*90*1.5-33*2+120)*10", 0]
|
||||
},
|
||||
"tail": {
|
||||
"tail_middle": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*5-120)*10+5", "-math.sin(q.anim_time*90*1.5-33*5-120)*4", 0]
|
||||
},
|
||||
"tail2": {
|
||||
"tail_middle2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*6-120)*8", "math.sin(q.anim_time*90*1.5-33*6-120)*6", 0]
|
||||
},
|
||||
"tail3": {
|
||||
"tail_middle3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*7-120)*8", "math.sin(q.anim_time*90*1.5-33*4-120)*8", 0]
|
||||
},
|
||||
"tail4": {
|
||||
"tail_middle4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*8-120)*8", "math.sin(q.anim_time*90*1.5-33*3-120)*8", 0]
|
||||
},
|
||||
"tail5": {
|
||||
"tail_middle5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9-120)*10", "-math.sin(q.anim_time*90*1.5-33*2-120)*10", 0]
|
||||
},
|
||||
"tail_left": {
|
||||
@@ -175,7 +175,7 @@
|
||||
"tail_right6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9+120)*6", "-math.sin(q.anim_time*90*1.5-33*2+120)*10", 0]
|
||||
},
|
||||
"tail6": {
|
||||
"tail_middle6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9+120)*6", "-math.sin(q.anim_time*90*1.5-33*2+120)*10", 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
@@ -223,19 +223,19 @@
|
||||
"tail_right5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*8+45)*16", "-math.sin(q.anim_time*90*2-33*8)*6", 0]
|
||||
},
|
||||
"tail": {
|
||||
"tail_middle": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*5+45)*10+5", "-math.sin(q.anim_time*90*4-33*6+45)*2", 0]
|
||||
},
|
||||
"tail2": {
|
||||
"tail_middle2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*6+45)*12", "-math.sin(q.anim_time*90*4-33*7+45)*2", 0]
|
||||
},
|
||||
"tail3": {
|
||||
"tail_middle3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*7+45)*14", "-math.sin(q.anim_time*90*4-33*8+45)*2", 0]
|
||||
},
|
||||
"tail4": {
|
||||
"tail_middle4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*8+45)*16", "-math.sin(q.anim_time*90*4-33*9+45)*2", 0]
|
||||
},
|
||||
"tail5": {
|
||||
"tail_middle5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*9+45)*16", "-math.sin(q.anim_time*90*4-33*10+45)*4", 0]
|
||||
},
|
||||
"tail_left": {
|
||||
@@ -345,7 +345,7 @@
|
||||
"tail_right6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*8+45)*14", "-math.sin(q.anim_time*90*2-33*8)*10", 0]
|
||||
},
|
||||
"tail6": {
|
||||
"tail_middle6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*9+45)*14", "-math.sin(q.anim_time*90*4-33*10+45)*6", 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
@@ -387,19 +387,19 @@
|
||||
"tail_right5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9+120)*10", "-math.sin(q.anim_time*90*1.5-33*2+120)*10", 0]
|
||||
},
|
||||
"tail": {
|
||||
"tail_middle": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*5-120)*10+5", "-math.sin(q.anim_time*90*1.5-33*5-120)*4", 0]
|
||||
},
|
||||
"tail2": {
|
||||
"tail_middle2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*6-120)*8", "math.sin(q.anim_time*90*1.5-33*6-120)*6", 0]
|
||||
},
|
||||
"tail3": {
|
||||
"tail_middle3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*7-120)*8", "math.sin(q.anim_time*90*1.5-33*4-120)*8", 0]
|
||||
},
|
||||
"tail4": {
|
||||
"tail_middle4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*8-120)*8", "math.sin(q.anim_time*90*1.5-33*3-120)*8", 0]
|
||||
},
|
||||
"tail5": {
|
||||
"tail_middle5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9-120)*10", "-math.sin(q.anim_time*90*1.5-33*2-120)*10", 0]
|
||||
},
|
||||
"tail_left": {
|
||||
@@ -472,7 +472,7 @@
|
||||
"tail_right6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9+120)*6", "-math.sin(q.anim_time*90*1.5-33*2+120)*10", 0]
|
||||
},
|
||||
"tail6": {
|
||||
"tail_middle6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9-120)*6", "-math.sin(q.anim_time*90*1.5-33*2-120)*10", 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
@@ -480,6 +480,255 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros.ride_ground_walk": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"hips": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-15", 0]
|
||||
},
|
||||
"torso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*15", 0]
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros.ride_ground_run": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"hips": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [0, 0, "q.r.yaw_change(0)*-10"]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-15", 0]
|
||||
},
|
||||
"torso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*15", 0]
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros.ride_jump": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, "2+math.sin(q.anim_time*90*12)/24", 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": ["q.r.velocity_y(0)*-20", 0, 0]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": ["q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10)*2", -15, 0]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-30)*3", 0, 0]
|
||||
},
|
||||
"tail_left3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-60)*4", 0, 0]
|
||||
},
|
||||
"tail_left4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-90)*5", 0, 0]
|
||||
},
|
||||
"tail_left5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-120)*6", 0, 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-150)*8", 0, 0]
|
||||
},
|
||||
"tail_middle": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10)*2", 0, 0]
|
||||
},
|
||||
"tail_middle2": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-30)*3", 0, 0]
|
||||
},
|
||||
"tail_middle3": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-60)*4", 0, 0]
|
||||
},
|
||||
"tail_middle4": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-90)*5", 0, 0]
|
||||
},
|
||||
"tail_middle5": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-120)*6", 0, 0]
|
||||
},
|
||||
"tail_middle6": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-150)*8", 0, 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-60)*2", 15, 0]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-90)*3", 0, 0]
|
||||
},
|
||||
"tail_right3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-120)*4", 0, 0]
|
||||
},
|
||||
"tail_right4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-150)*5", 0, 0]
|
||||
},
|
||||
"tail_right5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-180)*6", 0, 0]
|
||||
},
|
||||
"tail_right6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-210)*8", 0, 0]
|
||||
},
|
||||
"mane_bottom": {
|
||||
"rotation": ["math.sin(q.anim_time*90*20)*2", 0, 0]
|
||||
},
|
||||
"mane_top": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*20)*2", 0, 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": ["-30+math.sin(q.anim_time*90*20-60)/2+q.r.velocity_y(0)*40", 0, 0]
|
||||
},
|
||||
"leg_front_right2": {
|
||||
"rotation": ["40+math.sin(q.anim_time*90*20-150)+q.r.velocity_y(0)*30", 0, 0]
|
||||
},
|
||||
"leg_front_left": {
|
||||
"rotation": ["-25+math.sin(q.anim_time*90*20)/2+q.r.velocity_y(0)*40", 0, 0]
|
||||
},
|
||||
"leg_front_left2": {
|
||||
"rotation": ["40+math.sin(q.anim_time*90*20-90)+q.r.velocity_y(0)*30", 0, 0]
|
||||
},
|
||||
"leg_back_right": {
|
||||
"rotation": ["5+math.sin(q.anim_time*90*20)/2+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_right2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*20-90)+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_left": {
|
||||
"rotation": ["10+math.sin(q.anim_time*90*20-60)/2+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_left2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*20-150)+q.r.velocity_y(0)*20", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros.render": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"head_angle": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": [28.49002, 17.28889, 10.8585]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": [-2.61298, -9.65594, 15.22074]
|
||||
},
|
||||
"tail_right3": {
|
||||
"rotation": [0, -15, 0]
|
||||
},
|
||||
"tail_right4": {
|
||||
"rotation": [0, -27.5, 0]
|
||||
},
|
||||
"tail_right5": {
|
||||
"rotation": [0, -17.5, 0]
|
||||
},
|
||||
"tail_middle": {
|
||||
"rotation": [47.5, 0, 0]
|
||||
},
|
||||
"tail_middle2": {
|
||||
"rotation": [10.15375, 12.42297, 0.88796]
|
||||
},
|
||||
"tail_middle3": {
|
||||
"rotation": [-5.03364, 9.99043, -0.22117]
|
||||
},
|
||||
"tail_middle4": {
|
||||
"rotation": [0, 7.5, 0]
|
||||
},
|
||||
"tail_middle5": {
|
||||
"rotation": [17.5, -5, -5]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": [-5, 0, 0]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": [17.61435, 9.91358, -6.18155]
|
||||
},
|
||||
"tail_left3": {
|
||||
"rotation": [12.92638, 14.63639, 3.31914]
|
||||
},
|
||||
"tail_left4": {
|
||||
"rotation": [0, 37.5, 0]
|
||||
},
|
||||
"tail_left5": {
|
||||
"rotation": [0, 52.5, 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"leg_front_right2": {
|
||||
"rotation": [22.5, 0, 0]
|
||||
},
|
||||
"leg_front_right3": {
|
||||
"rotation": [22.5, 0, 0]
|
||||
},
|
||||
"leg_front_left2": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"leg_front_left3": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"leg_back_right2": {
|
||||
"rotation": [-10, 0, 0]
|
||||
},
|
||||
"leg_back_right3": {
|
||||
"rotation": [10, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros.blink": {
|
||||
"animation_length": 0.1667,
|
||||
"bones": {
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [-0.1, 0, -0.1],
|
||||
"0.125": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0.1, 0, -0.1],
|
||||
"0.125": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros.cry": {
|
||||
"animation_length": 2.125,
|
||||
"bones": {
|
||||
@@ -617,15 +866,15 @@
|
||||
},
|
||||
"position": {
|
||||
"0.0": {
|
||||
"post": [0, -0.5, 0],
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.4583": {
|
||||
"post": [0, -1, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.5417": [0, -0.5, 0],
|
||||
"1.7917": [0, -0.5, 0]
|
||||
"0.5417": [0, 0, 0],
|
||||
"1.7917": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"leg_front_right2": {
|
||||
@@ -711,6 +960,10 @@
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.3333": {
|
||||
"post": [-0.00259, -0.29316, -0.18789],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.5417": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
@@ -739,102 +992,6 @@
|
||||
"effect": "pokemon.tauros.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros.render": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"head_angle": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": [28.49002, 17.28889, 10.8585]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": [-2.61298, -9.65594, 15.22074]
|
||||
},
|
||||
"tail_right3": {
|
||||
"rotation": [0, -15, 0]
|
||||
},
|
||||
"tail_right4": {
|
||||
"rotation": [0, -27.5, 0]
|
||||
},
|
||||
"tail_right5": {
|
||||
"rotation": [0, -17.5, 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [47.5, 0, 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [10.15375, 12.42297, 0.88796]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": [-5.03364, 9.99043, -0.22117]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": [0, 7.5, 0]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": [17.5, -5, -5]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": [-5, 0, 0]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": [17.61435, 9.91358, -6.18155]
|
||||
},
|
||||
"tail_left3": {
|
||||
"rotation": [12.92638, 14.63639, 3.31914]
|
||||
},
|
||||
"tail_left4": {
|
||||
"rotation": [0, 37.5, 0]
|
||||
},
|
||||
"tail_left5": {
|
||||
"rotation": [0, 52.5, 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"leg_front_right2": {
|
||||
"rotation": [22.5, 0, 0]
|
||||
},
|
||||
"leg_front_right3": {
|
||||
"rotation": [22.5, 0, 0]
|
||||
},
|
||||
"leg_front_left2": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"leg_front_left3": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"leg_back_right2": {
|
||||
"rotation": [-10, 0, 0]
|
||||
},
|
||||
"leg_back_right3": {
|
||||
"rotation": [10, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros.blink": {
|
||||
"animation_length": 0.1667,
|
||||
"bones": {
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [-0.1, 0, -0.1],
|
||||
"0.125": [-0.1, 0, -0.1],
|
||||
"0.1667": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0.1, 0, -0.1],
|
||||
"0.125": [0.1, 0, -0.1],
|
||||
"0.1667": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+694
-2
@@ -227,7 +227,7 @@
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2)*20+10", 0, 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*4+45)*10+5", "math.sin(q.anim_time*90*2-33*4)*1+5", 0]
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*3+45)*12+5", "NaN-math.sin(q.anim_time*90*2-33*3+180)*1+5", 0]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*5+45)*12", "-math.sin(q.anim_time*90*2-33*5)*2+5", 0]
|
||||
@@ -257,7 +257,7 @@
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*9+45)*16", "-math.sin(q.anim_time*90*4-33*10+45)*4", 0]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*3+45)*12+5", "-math.sin(q.anim_time*90*2-33*3+180)*1-5", 0]
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*3+45)*12+5", "-math.sin(q.anim_time*90*2-33*3+180)*1+5", 0]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4*2-33*4+45)*10", "math.sin(q.anim_time*90*2-33*4+180)*2-5", 0]
|
||||
@@ -534,6 +534,684 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.ride_ground_walk": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*10", 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-15", 0]
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.ride_ground_run": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": [0, 0, "q.r.yaw_change(0)*-10"]
|
||||
},
|
||||
"torso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*15", 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-15", 0]
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.ride_jump_land": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, "2+math.sin(q.anim_time*90*12)/24", 0]
|
||||
},
|
||||
"mane_bottom": {
|
||||
"rotation": ["math.sin(q.anim_time*90*20)*2", 0, 0]
|
||||
},
|
||||
"mane_top": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*20)*2", 0, 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": ["-30+math.sin(q.anim_time*90*20-60)/2+q.r.velocity_y(0)*40", 0, 0]
|
||||
},
|
||||
"leg_front_right2": {
|
||||
"rotation": ["40+math.sin(q.anim_time*90*20-150)+q.r.velocity_y(0)*30", 0, 0]
|
||||
},
|
||||
"leg_front_left": {
|
||||
"rotation": ["-25+math.sin(q.anim_time*90*20)/2+q.r.velocity_y(0)*40", 0, 0]
|
||||
},
|
||||
"leg_front_left2": {
|
||||
"rotation": ["40+math.sin(q.anim_time*90*20-90)+q.r.velocity_y(0)*30", 0, 0]
|
||||
},
|
||||
"leg_back_right": {
|
||||
"rotation": ["5+math.sin(q.anim_time*90*20)/2+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_right2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*20-90)+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_left": {
|
||||
"rotation": ["10+math.sin(q.anim_time*90*20-60)/2+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_left2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*20-150)+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": ["q.r.velocity_y(0)*-20", 0, 0]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": ["q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10)*2", -15, 0]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-30)*3", 0, 0]
|
||||
},
|
||||
"tail_left3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-60)*4", 0, 0]
|
||||
},
|
||||
"tail_left4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-90)*5", 0, 0]
|
||||
},
|
||||
"tail_left5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-120)*6", 0, 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-150)*8", 0, 0]
|
||||
},
|
||||
"tail_middle": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10)*2", 0, 0]
|
||||
},
|
||||
"tail_middle2": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-30)*3", 0, 0]
|
||||
},
|
||||
"tail_middle3": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-60)*4", 0, 0]
|
||||
},
|
||||
"tail_middle4": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-90)*5", 0, 0]
|
||||
},
|
||||
"tail_middle5": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-120)*6", 0, 0]
|
||||
},
|
||||
"tail_middle6": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-150)*8", 0, 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-60)*2", 15, 0]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-90)*3", 0, 0]
|
||||
},
|
||||
"tail_right3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-120)*4", 0, 0]
|
||||
},
|
||||
"tail_right4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-150)*5", 0, 0]
|
||||
},
|
||||
"tail_right5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-180)*6", 0, 0]
|
||||
},
|
||||
"tail_right6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*10-210)*8", 0, 0]
|
||||
},
|
||||
"horn_glow_right": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right3": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left3": {
|
||||
"scale": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.surfacewater_idle": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, "-15+math.sin(q.anim_time*90)/2", 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": ["-5-math.sin(q.anim_time*90-90)/2", 0, 0]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [0, 0, "math.sin(q.anim_time*45-90)*2"]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": [-30, 0, 0]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5)*8", "math.sin(q.anim_time*90*(1.5/2))*3", 0]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": ["-5-math.sin(q.anim_time*90*1.5-30)*8", "math.sin(q.anim_time*90*(1.5/2)-30)*3", 0]
|
||||
},
|
||||
"tail_left3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-60)*8", "15+math.sin(q.anim_time*90*(1.5/2)-60)*3", 0]
|
||||
},
|
||||
"tail_left4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-90)*8", "15+math.sin(q.anim_time*90*(1.5/2)-90)*3", 0]
|
||||
},
|
||||
"tail_left5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-120)*8", "math.sin(q.anim_time*90*(1.5/2)-120)*3", 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-150)*8", "math.sin(q.anim_time*90*(1.5/2)-150)*3", 0]
|
||||
},
|
||||
"tail_left7": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-180)*8", "math.sin(q.anim_time*90*(1.5/2)-180)*3", 0]
|
||||
},
|
||||
"tail_middle": {
|
||||
"rotation": [2, 0, 0]
|
||||
},
|
||||
"tail_middle2": {
|
||||
"rotation": ["15-math.sin(q.anim_time*90*1.5)*8", "math.sin(q.anim_time*90*(1.5/2))*3", 0]
|
||||
},
|
||||
"tail_middle3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-30)*8", "math.sin(q.anim_time*90*(1.5/2)-30)*3", 0]
|
||||
},
|
||||
"tail_middle4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-60)*8", "math.sin(q.anim_time*90*(1.5/2)-60)*3", 0]
|
||||
},
|
||||
"tail_middle5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-90)*8", "math.sin(q.anim_time*90*(1.5/2)-90)*3", 0]
|
||||
},
|
||||
"tail_middle6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-120)*8", "math.sin(q.anim_time*90*(1.5/2)-120)*3", 0]
|
||||
},
|
||||
"tail_middle7": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-150)*8", "math.sin(q.anim_time*90*(1.5/2)-150)*3", 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5)*8", "math.sin(q.anim_time*90*(1.5/2))*3", 0]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": ["-5-math.sin(q.anim_time*90*1.5-30)*8", "math.sin(q.anim_time*90*(1.5/2)-30)*3", 0]
|
||||
},
|
||||
"tail_right3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-60)*8", "-15-math.sin(q.anim_time*90*(1.5/2)-60)*3", 0]
|
||||
},
|
||||
"tail_right4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-90)*8", "-15+math.sin(q.anim_time*90*(1.5/2)-90)*3", 0]
|
||||
},
|
||||
"tail_right5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-120)*8", "math.sin(q.anim_time*90*(1.5/2)-120)*3", 0]
|
||||
},
|
||||
"tail_right6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-150)*8", "math.sin(q.anim_time*90*(1.5/2)-150)*3", 0]
|
||||
},
|
||||
"tail_right7": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*1.5-180)*8", "math.sin(q.anim_time*90*(1.5/2)-180)*3", 0]
|
||||
},
|
||||
"torso2": {
|
||||
"rotation": ["-2.5-math.sin(q.anim_time*90-150)/2", 0, 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": ["-5-math.sin(q.anim_time*90-210)", 0, 0]
|
||||
},
|
||||
"mane_bottom": {
|
||||
"rotation": ["-47.5-math.sin(q.anim_time*90-120)*8", 0, 0]
|
||||
},
|
||||
"lower_mane_right": {
|
||||
"rotation": [0, 0, "math.sin(q.anim_time*90-120)*8"]
|
||||
},
|
||||
"lower_mane_left": {
|
||||
"rotation": [0, 0, "-math.sin(q.anim_time*90-120)*8"]
|
||||
},
|
||||
"mane_top": {
|
||||
"rotation": ["math.sin(q.anim_time*90-120)*8", 0, 0]
|
||||
},
|
||||
"mane_left_top": {
|
||||
"rotation": [0, 0, "-math.sin(q.anim_time*90-120)*8"]
|
||||
},
|
||||
"mane_right_top": {
|
||||
"rotation": [0, 0, "math.sin(q.anim_time*90-120)*8"]
|
||||
},
|
||||
"mane_left_bottom": {
|
||||
"rotation": [0, 0, "-math.sin(q.anim_time*90-120)*8"]
|
||||
},
|
||||
"mane_right_bottom": {
|
||||
"rotation": [0, 0, "math.sin(q.anim_time*90-120)*8"]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["-math.sin(q.anim_time*90-270)", 0, "math.sin(q.anim_time*45-150)*2"]
|
||||
},
|
||||
"horn_glow_right": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right3": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left3": {
|
||||
"scale": 0
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": [-5, 0, 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": ["math.sin(q.anim_time*90*2-60)*4", 0, 0],
|
||||
"position": [0, "-math.sin(q.anim_time*90*2)/4", "-math.cos(q.anim_time*90*2)/4"]
|
||||
},
|
||||
"leg_front_right2": {
|
||||
"rotation": ["20+math.sin(q.anim_time*90*2-120)*6", 0, 0]
|
||||
},
|
||||
"leg_front_right3": {
|
||||
"rotation": ["15+math.sin(q.anim_time*90*2-180)*8", 0, 0]
|
||||
},
|
||||
"leg_front_left": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*2-60)*4", 0, 0],
|
||||
"position": [0, "math.sin(q.anim_time*90*2)/4", "math.cos(q.anim_time*90*2)/4"]
|
||||
},
|
||||
"leg_front_left2": {
|
||||
"rotation": ["20-math.sin(q.anim_time*90*2-120)*6", 0, 0]
|
||||
},
|
||||
"leg_front_left3": {
|
||||
"rotation": ["15-math.sin(q.anim_time*90*2-180)*8", 0, 0]
|
||||
},
|
||||
"leg_back_right": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*2-60)*4", 0, 0],
|
||||
"position": [0, "math.sin(q.anim_time*90*2)/4", "math.cos(q.anim_time*90*2)/4"]
|
||||
},
|
||||
"leg_back_right2": {
|
||||
"rotation": ["-20-math.sin(q.anim_time*90*2-120)*15", 0, 0]
|
||||
},
|
||||
"leg_back_right3": {
|
||||
"rotation": ["12.5-math.sin(q.anim_time*90*2-180)*8", 0, 0]
|
||||
},
|
||||
"leg_back_left": {
|
||||
"rotation": ["math.sin(q.anim_time*90*2-60)*4", 0, 0],
|
||||
"position": [0, "-math.sin(q.anim_time*90*2)/4", "-math.cos(q.anim_time*90*2)/4"]
|
||||
},
|
||||
"leg_back_left2": {
|
||||
"rotation": ["-20+math.sin(q.anim_time*90*2-120)*15", 0, 0]
|
||||
},
|
||||
"leg_back_left3": {
|
||||
"rotation": ["12.5+math.sin(q.anim_time*90*2-180)*8", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.surfacewater_swim": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, "-15+math.sin(q.anim_time*90*3)/4", 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": ["-10-math.sin(q.anim_time*90*3)", 0, 0]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": [15, 0, "math.mod(q.anim_time*2,1)*360"]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": [-15, 17.5, 27.5]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": [0, -5, 0]
|
||||
},
|
||||
"tail_left3": {
|
||||
"rotation": [0, -5, 0]
|
||||
},
|
||||
"tail_left4": {
|
||||
"rotation": [0, 12.5, 0]
|
||||
},
|
||||
"tail_left5": {
|
||||
"rotation": [15, 12.5, 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
"rotation": [17.5, 15, 0]
|
||||
},
|
||||
"tail_left7": {
|
||||
"rotation": [12.5, 15, 0]
|
||||
},
|
||||
"tail_middle": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"tail_middle2": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"tail_middle3": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"tail_middle4": {
|
||||
"rotation": [20, 0, 0]
|
||||
},
|
||||
"tail_middle5": {
|
||||
"rotation": [15, -22.5, 0]
|
||||
},
|
||||
"tail_middle6": {
|
||||
"rotation": [10, -20, 0]
|
||||
},
|
||||
"tail_middle7": {
|
||||
"rotation": [10, -22.5, 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": [-15, -17.5, -27.5]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": [0, 5, 0]
|
||||
},
|
||||
"tail_right3": {
|
||||
"rotation": [0, 5, 0]
|
||||
},
|
||||
"tail_right4": {
|
||||
"rotation": [0, -12.5, 0]
|
||||
},
|
||||
"tail_right5": {
|
||||
"rotation": [-15, -12.5, 0]
|
||||
},
|
||||
"tail_right6": {
|
||||
"rotation": [-17.5, -15, 0]
|
||||
},
|
||||
"tail_right7": {
|
||||
"rotation": [-12.5, -15, 0]
|
||||
},
|
||||
"tail_right8": {
|
||||
"rotation": [-25, 0, 0]
|
||||
},
|
||||
"torso2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-60)", 0, 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": ["2.5-math.sin(q.anim_time*90*3-120)", 0, 0]
|
||||
},
|
||||
"mane_bottom": {
|
||||
"rotation": ["25+math.sin(q.anim_time*90*3)*8", 0, 0]
|
||||
},
|
||||
"lower_mane_right": {
|
||||
"rotation": ["math.sin(q.anim_time*90*3+90)*4", 0, 0]
|
||||
},
|
||||
"lower_mane_left": {
|
||||
"rotation": ["math.sin(q.anim_time*90*3+90)*4", 0, 0]
|
||||
},
|
||||
"mane_left_top": {
|
||||
"rotation": ["math.sin(q.anim_time*90*3-30)*8", 0, 0]
|
||||
},
|
||||
"mane_right_top": {
|
||||
"rotation": ["math.sin(q.anim_time*90*3-30)*8", 0, 0]
|
||||
},
|
||||
"mane_left_bottom": {
|
||||
"rotation": ["math.sin(q.anim_time*90*3+30)*8", 0, 0]
|
||||
},
|
||||
"mane_right_bottom": {
|
||||
"rotation": ["math.sin(q.anim_time*90*3+30)*8", 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["-25-math.sin(q.anim_time*90*3-150)", 0, 0]
|
||||
},
|
||||
"horn_glow_right": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right3": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left3": {
|
||||
"scale": 0
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-60)", 0, 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": ["2.5-math.sin(q.anim_time*90*3-120)", 0, 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": ["5-math.sin(q.anim_time*90*3-120)*4", 0, 0],
|
||||
"position": [0, "-2+math.sin(q.anim_time*90*3-30)/4", "math.cos(q.anim_time*90*3-30)/4"]
|
||||
},
|
||||
"leg_front_right2": {
|
||||
"rotation": ["57.5-math.sin(q.anim_time*90*3-180)*8", 0, 0]
|
||||
},
|
||||
"leg_front_right3": {
|
||||
"rotation": ["32.5-math.sin(q.anim_time*90*3-210)*6", 0, 0],
|
||||
"position": [0, 0.25, 0]
|
||||
},
|
||||
"leg_front_left": {
|
||||
"rotation": ["5-math.sin(q.anim_time*90*3-90)*4", 0, 0],
|
||||
"position": [0, "-2+math.sin(q.anim_time*90*3)/4", "math.cos(q.anim_time*90*3)/4"]
|
||||
},
|
||||
"leg_front_left2": {
|
||||
"rotation": ["57.5-math.sin(q.anim_time*90*3-150)*8", 0, 0]
|
||||
},
|
||||
"leg_front_left3": {
|
||||
"rotation": ["32.5-math.sin(q.anim_time*90*3-180)*6", 0, 0],
|
||||
"position": [0, 0.25, 0]
|
||||
},
|
||||
"leg_back_right": {
|
||||
"rotation": ["57.5+math.sin(q.anim_time*90*3-120)*4", 0, 0],
|
||||
"position": [0, "-math.sin(q.anim_time*90*3)/4", "-math.cos(q.anim_time*90*3)/4"]
|
||||
},
|
||||
"leg_back_right2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*3-180)*4", 0, 0]
|
||||
},
|
||||
"leg_back_right3": {
|
||||
"rotation": ["15+math.sin(q.anim_time*90*3-210)*6", 0, 0]
|
||||
},
|
||||
"leg_back_left": {
|
||||
"rotation": ["42.5+math.sin(q.anim_time*90*3-90)*4", 0, 0],
|
||||
"position": [0, "-math.sin(q.anim_time*90*3)/4", "-math.cos(q.anim_time*90*3)/4"]
|
||||
},
|
||||
"leg_back_left2": {
|
||||
"rotation": ["-37.5+math.sin(q.anim_time*90*3-150)*4", 0, 0]
|
||||
},
|
||||
"leg_back_left3": {
|
||||
"rotation": ["15+math.sin(q.anim_time*90*3-180)*6", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.ride_surfacewater_swim": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*10", 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*10", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*10", 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-10", 0]
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*10", 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*10", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.ride_jump_liquid": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, "2+math.sin(q.anim_time*90*12)/24", 0]
|
||||
},
|
||||
"mane_bottom": {
|
||||
"rotation": ["math.sin(q.anim_time*90*20)*2", 0, 0]
|
||||
},
|
||||
"mane_top": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*20)*2", 0, 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": ["-30+math.sin(q.anim_time*90*20-60)/2+q.r.velocity_y(0)*40", 0, 0]
|
||||
},
|
||||
"leg_front_right2": {
|
||||
"rotation": ["40+math.sin(q.anim_time*90*20-150)+q.r.velocity_y(0)*30", 0, 0]
|
||||
},
|
||||
"leg_front_left": {
|
||||
"rotation": ["-25+math.sin(q.anim_time*90*20)/2+q.r.velocity_y(0)*40", 0, 0]
|
||||
},
|
||||
"leg_front_left2": {
|
||||
"rotation": ["40+math.sin(q.anim_time*90*20-90)+q.r.velocity_y(0)*30", 0, 0]
|
||||
},
|
||||
"leg_back_right": {
|
||||
"rotation": ["5+math.sin(q.anim_time*90*20)/2+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_right2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*20-90)+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_left": {
|
||||
"rotation": ["10+math.sin(q.anim_time*90*20-60)/2+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_left2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*20-150)+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": ["q.r.velocity_y(0)*-20", 0, 0]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": [15, 0, "math.mod(q.anim_time*1,1)*360"]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": [-15, 17.5, 27.5]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": [0, -5, 0]
|
||||
},
|
||||
"tail_left3": {
|
||||
"rotation": [0, -5, 0]
|
||||
},
|
||||
"tail_left4": {
|
||||
"rotation": [0, 12.5, 0]
|
||||
},
|
||||
"tail_left5": {
|
||||
"rotation": [15, 12.5, 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
"rotation": [17.5, 15, 0]
|
||||
},
|
||||
"tail_left7": {
|
||||
"rotation": [12.5, 15, 0]
|
||||
},
|
||||
"tail_middle": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"tail_middle2": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"tail_middle3": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"tail_middle4": {
|
||||
"rotation": [20, 0, 0]
|
||||
},
|
||||
"tail_middle5": {
|
||||
"rotation": [15, -22.5, 0]
|
||||
},
|
||||
"tail_middle6": {
|
||||
"rotation": [10, -20, 0]
|
||||
},
|
||||
"tail_middle7": {
|
||||
"rotation": [10, -22.5, 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": [-15, -17.5, -27.5]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": [0, 5, 0]
|
||||
},
|
||||
"tail_right3": {
|
||||
"rotation": [0, 5, 0]
|
||||
},
|
||||
"tail_right4": {
|
||||
"rotation": [0, -12.5, 0]
|
||||
},
|
||||
"tail_right5": {
|
||||
"rotation": [-15, -12.5, 0]
|
||||
},
|
||||
"tail_right6": {
|
||||
"rotation": [-17.5, -15, 0]
|
||||
},
|
||||
"tail_right7": {
|
||||
"rotation": [-12.5, -15, 0]
|
||||
},
|
||||
"tail_right8": {
|
||||
"rotation": [-25, 0, 0]
|
||||
},
|
||||
"horn_glow_right": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right3": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left3": {
|
||||
"scale": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.render": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
@@ -893,6 +1571,20 @@
|
||||
"effect": "pokemon.tauros.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_aqua.glow": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"head_marking_glow": {
|
||||
"position": [0, 0.1, -0.1]
|
||||
},
|
||||
"head_markings_top": {
|
||||
"position": [0, -0.1, 0]
|
||||
},
|
||||
"head_markings_glow_top": {
|
||||
"position": [0, 0.1, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+173
-39
@@ -402,27 +402,9 @@
|
||||
"head_correction": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4-90)*0.5-1", 0, 0]
|
||||
},
|
||||
"mane_top": {
|
||||
"rotation": ["math.sin(q.anim_time*90*4-45)*4-4", 0, 0]
|
||||
},
|
||||
"mane_bottom": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4-45)*4-4", 0, 0]
|
||||
},
|
||||
"tail_right": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*5+120)*10+5", "-math.sin(q.anim_time*90*1.5-33*5+120)*4", 0]
|
||||
},
|
||||
"tail_right2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*6+120)*8", "math.sin(q.anim_time*90*1.5-33*6+120)*6", 0]
|
||||
},
|
||||
"tail_right3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*7+120)*8", "math.sin(q.anim_time*90*1.5-33*4+120)*8", 0]
|
||||
},
|
||||
"tail_right4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*8+120)*8", "math.sin(q.anim_time*90*1.5-33*3+120)*8", 0]
|
||||
},
|
||||
"tail_right5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9+120)*10", "-math.sin(q.anim_time*90*1.5-33*2+120)*10", 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*5-120)*10+5", "-math.sin(q.anim_time*90*1.5-33*5-120)*4", 0]
|
||||
},
|
||||
@@ -438,21 +420,6 @@
|
||||
"tail5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9-120)*10", "-math.sin(q.anim_time*90*1.5-33*2-120)*10", 0]
|
||||
},
|
||||
"tail_left": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*5)*10+5", "-math.sin(q.anim_time*90*1.5-33*5)*4", 0]
|
||||
},
|
||||
"tail_left2": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*6)*8", "math.sin(q.anim_time*90*1.5-33*6)*6", 0]
|
||||
},
|
||||
"tail_left3": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*7)*8", "math.sin(q.anim_time*90*1.5-33*4)*8", 0]
|
||||
},
|
||||
"tail_left4": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*8)*8", "math.sin(q.anim_time*90*1.5-33*3)*8", 0]
|
||||
},
|
||||
"tail_left5": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9)*10", "-math.sin(q.anim_time*90*1.5-33*2)*10", 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*4-66)*3-3", 0, "-math.sin(q.anim_time*90*2+66)*0.5-math.sin(q.anim_time*90*2-45)*0.2"],
|
||||
"position": [
|
||||
@@ -505,15 +472,9 @@
|
||||
"leg_back_left3": {
|
||||
"rotation": ["-3.5-1*(math.sin(q.anim_time*90*4-90)*1+1+math.sin(q.anim_time*90*4-90)*2-2-math.sin(q.anim_time*90*4-90)*4-6)", 0, 0]
|
||||
},
|
||||
"tail_right6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9+120)*6", "-math.sin(q.anim_time*90*1.5-33*2+120)*10", 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9-120)*6", "-math.sin(q.anim_time*90*1.5-33*2-120)*10", 0]
|
||||
},
|
||||
"tail_left6": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*3-33*9)*6", "-math.sin(q.anim_time*90*1.5-33*2)*10", 0]
|
||||
},
|
||||
"horn_glow_left": {
|
||||
"scale": 0
|
||||
},
|
||||
@@ -534,6 +495,165 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_blaze.ride_ground_walk": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*10", 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [0, "q.r.yaw_change(2)*-10", 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": [0, "q.r.yaw_change(4)*-10", 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": [0, "q.r.yaw_change(6)*-15", 0]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": [0, "q.r.yaw_change(8)*-15", 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": [0, "q.r.yaw_change(10)*-15", 0]
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_blaze.ride_ground_run": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": [0, 0, "q.r.yaw_change(0)*-10"]
|
||||
},
|
||||
"torso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"torso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*15", 0]
|
||||
},
|
||||
"tails": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-15", 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*-5", 0]
|
||||
},
|
||||
"ftorso2": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
},
|
||||
"ftorso3": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*7.5", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_blaze.ride_jump": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, "2+math.sin(q.anim_time*90*12)/24", 0]
|
||||
},
|
||||
"mane_bottom": {
|
||||
"rotation": ["math.sin(q.anim_time*90*20)*2", 0, 0]
|
||||
},
|
||||
"leg_front_right": {
|
||||
"rotation": ["-30+math.sin(q.anim_time*90*20-60)/2+q.r.velocity_y(0)*40", 0, 0]
|
||||
},
|
||||
"leg_front_right2": {
|
||||
"rotation": ["40+math.sin(q.anim_time*90*20-150)+q.r.velocity_y(0)*30", 0, 0]
|
||||
},
|
||||
"leg_front_left": {
|
||||
"rotation": ["-25+math.sin(q.anim_time*90*20)/2+q.r.velocity_y(0)*40", 0, 0]
|
||||
},
|
||||
"leg_front_left2": {
|
||||
"rotation": ["40+math.sin(q.anim_time*90*20-90)+q.r.velocity_y(0)*30", 0, 0]
|
||||
},
|
||||
"leg_back_right": {
|
||||
"rotation": ["5+math.sin(q.anim_time*90*20)/2+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_right2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*20-90)+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_left": {
|
||||
"rotation": ["10+math.sin(q.anim_time*90*20-60)/2+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"leg_back_left2": {
|
||||
"rotation": ["-15+math.sin(q.anim_time*90*20-150)+q.r.velocity_y(0)*20", 0, 0]
|
||||
},
|
||||
"hips": {
|
||||
"rotation": ["q.r.velocity_y(0)*-20", 0, 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": ["q.r.velocity_y(0)*20+math.sin(q.anim_time*90*10)*2", 0, 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-30)*3", 0, 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-60)*4", 0, 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-90)*5", 0, 0]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-120)*6", 0, 0]
|
||||
},
|
||||
"tail6": {
|
||||
"rotation": ["math.sin(q.anim_time*90*10-150)*8", 0, 0]
|
||||
},
|
||||
"mane_right": {
|
||||
"rotation": [0, "NaN-math.sin(q.anim_time*90*20-180)*2", 0]
|
||||
},
|
||||
"mane_left": {
|
||||
"rotation": [0, "-math.sin(q.anim_time*90*20-180)*2", 0]
|
||||
},
|
||||
"mane_top_fur": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*20)*2", 0, 0]
|
||||
},
|
||||
"mane_middle_right": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*20-30)*2", 0, 0]
|
||||
},
|
||||
"mane_middle_left": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*20-90)*2", 0, 0]
|
||||
},
|
||||
"horn_glow_right": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_right3": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left2": {
|
||||
"scale": 0
|
||||
},
|
||||
"horn_glow_left3": {
|
||||
"scale": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_blaze.render": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
@@ -911,6 +1031,20 @@
|
||||
"effect": "pokemon.tauros.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tauros_paldean_blaze.glow": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"head_markings_top": {
|
||||
"position": [0, -0.1, 0]
|
||||
},
|
||||
"head_markings_glow_top": {
|
||||
"position": [0, 0.1, 0]
|
||||
},
|
||||
"head_marking_glow": {
|
||||
"position": [0, 0.1, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1009
File diff suppressed because it is too large
Load Diff
+17271
-163
File diff suppressed because it is too large
Load Diff
+448
-68
@@ -3600,28 +3600,64 @@
|
||||
"left_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.375": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.9583": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"2.5": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.9583": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.375": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.9583": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"2.5": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.9583": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"closed": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.375": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"1.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.9583": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"2.5": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.9583": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"front_neck_fluff_lower": {
|
||||
@@ -4413,28 +4449,64 @@
|
||||
"left_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.8333": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"2.0": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"2.2917": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.8333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.8333": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"2.0": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"2.2917": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.8333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"closed": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.8333": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"1.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
|
||||
"2.0": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"2.2917": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.8333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"front_neck_fluff_lower": {
|
||||
@@ -4575,25 +4647,49 @@
|
||||
"left_pupil": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, -0.8, 0]},
|
||||
"2.2917": {"pre": [0, -0.8, 0], "post": [0, 0, 0]}
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, -0.8, 0]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [0, -0.8, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"1.25": {"pre": [1, 1, 1], "post": [1, 0.5, 1]},
|
||||
"2.2917": {"pre": [1, 0.5, 1], "post": [1, 1, 1]}
|
||||
"1.25": {
|
||||
"pre": [1, 1, 1],
|
||||
"post": [1, 0.5, 1]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [1, 0.5, 1],
|
||||
"post": [1, 1, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_pupil": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, -0.8, 0]},
|
||||
"2.2917": {"pre": [0, -0.8, 0], "post": [0, 0, 0]}
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, -0.8, 0]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [0, -0.8, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"1.25": {"pre": [1, 1, 1], "post": [1, 0.5, 1]},
|
||||
"2.2917": {"pre": [1, 0.5, 1], "post": [1, 1, 1]}
|
||||
"1.25": {
|
||||
"pre": [1, 1, 1],
|
||||
"post": [1, 0.5, 1]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [1, 0.5, 1],
|
||||
"post": [1, 1, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"back_neck_fluff_lower": {
|
||||
@@ -5407,28 +5503,64 @@
|
||||
"left_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"0.7917": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.375": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.875": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"0.7917": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.875": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"0.7917": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.375": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.875": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"0.7917": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.875": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"closed": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"0.7917": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.375": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"1.875": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"0.7917": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"1.875": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"front_neck_fluff_lower": {
|
||||
@@ -6512,28 +6644,64 @@
|
||||
"left_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"0.7917": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.375": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.875": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"0.7917": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.875": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"0.7917": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.375": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.875": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"0.7917": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.875": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"closed": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"0.7917": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.375": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"1.875": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"0.7917": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"1.875": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"front_neck_fluff_lower": {
|
||||
@@ -7414,22 +7582,40 @@
|
||||
"left_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.9583": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.9583": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.9583": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.9583": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"closed": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"1.9583": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"1.9583": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"front_neck_fluff_lower": {
|
||||
@@ -7707,22 +7893,40 @@
|
||||
"closed": {
|
||||
"position": {
|
||||
"0.0": [0, 0, -0.1],
|
||||
"0.125": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
|
||||
"0.1667": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.125": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"0.1667": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"left_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.125": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
|
||||
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.125": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"right_eye": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.125": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
|
||||
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.125": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"0.1667": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7881,6 +8085,182 @@
|
||||
"effect": "pokemon.slaking.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.slaking.ride_ground": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*20", "q.r.yaw_change(0)*-8"]
|
||||
},
|
||||
"upper_torso": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*10", 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*30", 0]
|
||||
},
|
||||
"legs": {
|
||||
"rotation": [0, "q.r.yaw_change(0)*5", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.slaking.ride_jump": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, "2+math.clamp((q.r.velocity_y(0)*3),0,3)+math.sin(q.anim_time*90*12)*0.1", 0]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": ["30+q.r.velocity_y(0)*-20", 0, 0]
|
||||
},
|
||||
"upper_torso": {
|
||||
"rotation": ["10+q.r.velocity_y(0)*10", 0, 0]
|
||||
},
|
||||
"right_upper_arm": {
|
||||
"rotation": ["-17.5+q.r.velocity_y(0)*20", "-5+q.r.velocity_y(0)*20-math.sin(q.anim_time*90*20)/8", "-17.5+q.r.velocity_y(0)*-20"]
|
||||
},
|
||||
"right_lower_arm": {
|
||||
"rotation": [0, "-60+q.r.velocity_y(0)*20-math.sin(q.anim_time*90*20-90)/2", 0]
|
||||
},
|
||||
"right_hand": {
|
||||
"rotation": [0, 0, -20]
|
||||
},
|
||||
"right_index_finger": {
|
||||
"rotation": [0, 0, -30]
|
||||
},
|
||||
"right_index_finger_tip": {
|
||||
"rotation": [0, 0, -62.5]
|
||||
},
|
||||
"right_middle_finger": {
|
||||
"rotation": [0, 0, -25]
|
||||
},
|
||||
"right_middle_finger_tip": {
|
||||
"rotation": [0, 0, -75]
|
||||
},
|
||||
"right_ring_finger": {
|
||||
"rotation": [0, 0, -32.5]
|
||||
},
|
||||
"right_ring_finger_tip": {
|
||||
"rotation": [0, 0, -80]
|
||||
},
|
||||
"right_pinky_finger": {
|
||||
"rotation": [0, 0, -40]
|
||||
},
|
||||
"right_pinky_finger_tip": {
|
||||
"rotation": [0, 0, -77.5]
|
||||
},
|
||||
"right_thumb": {
|
||||
"rotation": [0, -25, -22.5]
|
||||
},
|
||||
"right_thumb_tip": {
|
||||
"rotation": [0, 50, 0]
|
||||
},
|
||||
"left_upper_arm": {
|
||||
"rotation": ["q.r.velocity_y(0)*20", "5+q.r.velocity_y(0)*-20+math.sin(q.anim_time*90*20)/8", "17.5+q.r.velocity_y(0)*20"]
|
||||
},
|
||||
"left_lower_arm": {
|
||||
"rotation": [0, "47.5+q.r.velocity_y(0)*-20+math.sin(q.anim_time*90*20-90)/2", 0]
|
||||
},
|
||||
"left_hand": {
|
||||
"rotation": [0, 0, 20]
|
||||
},
|
||||
"left_index_finger": {
|
||||
"rotation": [0, 0, 30]
|
||||
},
|
||||
"left_index_finger_tip": {
|
||||
"rotation": [0, 0, 62.5]
|
||||
},
|
||||
"left_middle_finger": {
|
||||
"rotation": [0, 0, 25]
|
||||
},
|
||||
"left_middle_finger_tip": {
|
||||
"rotation": [0, 0, 75]
|
||||
},
|
||||
"left_ring_finger": {
|
||||
"rotation": [0, 0, 32.5]
|
||||
},
|
||||
"left_ring_finger_tip": {
|
||||
"rotation": [0, 0, 80]
|
||||
},
|
||||
"left_pinky_finger": {
|
||||
"rotation": [0, 0, 40]
|
||||
},
|
||||
"left_pinky_finger_tip": {
|
||||
"rotation": [0, 0, 77.5]
|
||||
},
|
||||
"left_thumb": {
|
||||
"rotation": [0, 25, 22.5]
|
||||
},
|
||||
"left_thumb_tip": {
|
||||
"rotation": [0, -50, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["math.clamp((q.r.velocity_y(0)*30),-30,-10)+math.sin(q.anim_time*90*20)/8", 0, 0]
|
||||
},
|
||||
"left_head_tuft": {
|
||||
"rotation": [0, "-17.5+math.sin(q.anim_time*90*20)*2", 0]
|
||||
},
|
||||
"right_head_tuft": {
|
||||
"rotation": [0, "17.5-math.sin(q.anim_time*90*20-90)*2", 0]
|
||||
},
|
||||
"front_neck_fluff_lower": {
|
||||
"rotation": ["math.sin(q.anim_time*90*20)", 0, 0]
|
||||
},
|
||||
"front_neck_fluff_upper": {
|
||||
"rotation": ["-2.5+math.sin(q.anim_time*90*20-90)", 0, 0]
|
||||
},
|
||||
"back_neck_fluff_lower": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*20)", 0, 0]
|
||||
},
|
||||
"back_neck_fluff_upper": {
|
||||
"rotation": ["-math.sin(q.anim_time*90*20-90)", 0, 0]
|
||||
},
|
||||
"left_neck_fluff_lower": {
|
||||
"rotation": [0, 0, "math.sin(q.anim_time*90*20)"]
|
||||
},
|
||||
"left_neck_fluff_upper": {
|
||||
"rotation": [0, 0, "math.sin(q.anim_time*90*20-90)"]
|
||||
},
|
||||
"right_neck_fluff_lower": {
|
||||
"rotation": [0, 0, "-math.sin(q.anim_time*90*20)"]
|
||||
},
|
||||
"right_neck_fluff_upper": {
|
||||
"rotation": [0, 0, "-math.sin(q.anim_time*90*20-90)"]
|
||||
},
|
||||
"left_upper_leg": {
|
||||
"rotation": ["-45+q.r.velocity_y(0)*30+math.sin(q.anim_time*90*20-60)/4", -17.5, 0]
|
||||
},
|
||||
"left_lower_leg": {
|
||||
"rotation": ["55+math.clamp((q.r.velocity_y(0)*30),-30,0)+math.sin(q.anim_time*90*20-150)/2", 0, 0]
|
||||
},
|
||||
"left_foot": {
|
||||
"rotation": [2.5, 0, 0]
|
||||
},
|
||||
"left_small_toes": {
|
||||
"rotation": ["27.5+math.clamp((q.r.velocity_y(0)*30),-27.5,0)", 0, 0]
|
||||
},
|
||||
"left_big_toe": {
|
||||
"rotation": ["10+math.clamp((q.r.velocity_y(0)*10),-105,0)", 0, 0]
|
||||
},
|
||||
"right_upper_leg": {
|
||||
"rotation": ["-30+q.r.velocity_y(0)*30+math.sin(q.anim_time*90*20)/4", 15, 0]
|
||||
},
|
||||
"right_lower_leg": {
|
||||
"rotation": ["60+math.clamp((q.r.velocity_y(0)*40),-40,0)+math.sin(q.anim_time*90*20-90)/2", 0, 0]
|
||||
},
|
||||
"right_foot": {
|
||||
"rotation": [2.5, 0, 0]
|
||||
},
|
||||
"right_big_toe": {
|
||||
"rotation": ["10+math.clamp((q.r.velocity_y(0)*10),-105,0)", 0, 0]
|
||||
},
|
||||
"right_small_toes": {
|
||||
"rotation": ["27.5+math.clamp((q.r.velocity_y(0)*30),-27.5,0)", 0, 0]
|
||||
},
|
||||
"locator_seat_1": {
|
||||
"rotation": [-40, 0, 0],
|
||||
"position": [0, -5, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8221
-36
File diff suppressed because it is too large
Load Diff
+79
-84
@@ -7,8 +7,8 @@
|
||||
"texture_width": 128,
|
||||
"texture_height": 128,
|
||||
"visible_bounds_width": 10,
|
||||
"visible_bounds_height": 3.5,
|
||||
"visible_bounds_offset": [0, 1.25, 0]
|
||||
"visible_bounds_height": 2.5,
|
||||
"visible_bounds_offset": [0, 0.75, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
@@ -132,17 +132,17 @@
|
||||
{
|
||||
"name": "locator_seat_1",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 18.25, 3.75],
|
||||
"pivot": [0, 15.25, 3.75],
|
||||
"locators": {
|
||||
"seat_1": [0, 18.25, 3.75]
|
||||
"seat_1": [0, 15.25, 3.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_seat_2",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 15, 17],
|
||||
"pivot": [0, 12, 17],
|
||||
"locators": {
|
||||
"seat_2": [0, 15, 17]
|
||||
"seat_2": [0, 12, 17]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -164,11 +164,6 @@
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "neck",
|
||||
"pivot": [0, 4.75, -34.5]
|
||||
},
|
||||
{
|
||||
"name": "head_ai",
|
||||
"parent": "head",
|
||||
"pivot": [0, 4.75, -34.5],
|
||||
"cubes": [
|
||||
{"origin": [-5.5, 0, -39], "size": [11, 10, 10], "inflate": 0.21, "uv": [0, 93]},
|
||||
@@ -176,74 +171,48 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 1.85, -38.5],
|
||||
"cubes": [
|
||||
{"origin": [-4, -0.15, -41.5], "size": [8, 2, 3], "uv": [58, 35]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_mouth",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 1.75, -39.2],
|
||||
"name": "locator_head",
|
||||
"parent": "head",
|
||||
"pivot": [0, 10.25, -37],
|
||||
"locators": {
|
||||
"mouth": [0, 1.75, -39.2],
|
||||
"special": [0, 1.75, -39.2]
|
||||
"head": [0, 10.25, -37]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 1.75, -41.45],
|
||||
"name": "locator_item_hat",
|
||||
"parent": "head",
|
||||
"pivot": [0, 10.25, -34.75],
|
||||
"locators": {
|
||||
"item": [0, 1.75, -41.45]
|
||||
"item_hat": [0, 10.25, -34.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 1.8, -41.5],
|
||||
"name": "locator_face",
|
||||
"parent": "head",
|
||||
"pivot": [0, 4.7, -42.15],
|
||||
"locators": {
|
||||
"jaw2": [0, 1.8, -41.5]
|
||||
"face": [0, 4.7, -42.15]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "snout",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 3.88, -39.15],
|
||||
"cubes": [
|
||||
{"origin": [-5, 1.75, -42.15], "size": [10, 3, 3], "uv": [6, 122]},
|
||||
{"origin": [-1.5, 4.26, -41.15], "size": [3, 1, 1], "uv": [80, 35]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "snout",
|
||||
"pivot": [0, 1.75, -40.65],
|
||||
"name": "locator_item_face",
|
||||
"parent": "head",
|
||||
"pivot": [0, 6.2, -39.2],
|
||||
"locators": {
|
||||
"jaw1": [0, 1.75, -40.65]
|
||||
"item_face": [0, 6.2, -39.2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tooth_left",
|
||||
"parent": "snout",
|
||||
"pivot": [4, 2, -40.65],
|
||||
"cubes": [
|
||||
{"origin": [3.5, 0, -41.15], "size": [1, 2, 1], "uv": [80, 37]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tooth_right",
|
||||
"parent": "snout",
|
||||
"pivot": [-4, 2, -40.65],
|
||||
"cubes": [
|
||||
{"origin": [-4.5, 0, -41.15], "size": [1, 2, 1], "uv": [84, 37]}
|
||||
]
|
||||
"name": "locator_horn",
|
||||
"parent": "head",
|
||||
"pivot": [0, 13.15, -34.75],
|
||||
"locators": {
|
||||
"horn": [0, 13.15, -34.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eyes",
|
||||
"parent": "head_ai",
|
||||
"parent": "head",
|
||||
"pivot": [3.5, 6.5, -39.27]
|
||||
},
|
||||
{
|
||||
@@ -385,43 +354,69 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_horn",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 13.15, -34.75],
|
||||
"name": "snout",
|
||||
"parent": "head",
|
||||
"pivot": [0, 3.88, -39.15],
|
||||
"cubes": [
|
||||
{"origin": [-5, 1.75, -42.15], "size": [10, 3, 3], "uv": [6, 122]},
|
||||
{"origin": [-1.5, 4.26, -41.15], "size": [3, 1, 1], "uv": [80, 35]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "snout",
|
||||
"pivot": [0, 1.75, -40.65],
|
||||
"locators": {
|
||||
"horn": [0, 13.15, -34.75]
|
||||
"jaw1": [0, 1.75, -40.65]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_face",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 6.2, -39.2],
|
||||
"name": "tooth_left",
|
||||
"parent": "snout",
|
||||
"pivot": [4, 2, -40.65],
|
||||
"cubes": [
|
||||
{"origin": [3.5, 0, -41.15], "size": [1, 2, 1], "uv": [80, 37]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tooth_right",
|
||||
"parent": "snout",
|
||||
"pivot": [-4, 2, -40.65],
|
||||
"cubes": [
|
||||
{"origin": [-4.5, 0, -41.15], "size": [1, 2, 1], "uv": [84, 37]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw",
|
||||
"parent": "head",
|
||||
"pivot": [0, 1.85, -38.5],
|
||||
"cubes": [
|
||||
{"origin": [-4, -0.15, -41.5], "size": [8, 2, 3], "uv": [58, 35]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_mouth",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 1.75, -39.2],
|
||||
"locators": {
|
||||
"item_face": [0, 6.2, -39.2]
|
||||
"mouth": [0, 1.75, -39.2],
|
||||
"special": [0, 1.75, -39.2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_face",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 4.7, -42.15],
|
||||
"name": "locator_item",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 1.75, -41.45],
|
||||
"locators": {
|
||||
"face": [0, 4.7, -42.15]
|
||||
"item": [0, 1.75, -41.45]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_hat",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 10.25, -34.75],
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 1.8, -41.5],
|
||||
"locators": {
|
||||
"item_hat": [0, 10.25, -34.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_head",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 10.25, -37],
|
||||
"locators": {
|
||||
"head": [0, 10.25, -37]
|
||||
"jaw2": [0, 1.8, -41.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+172
-3
@@ -54,17 +54,17 @@
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 9.5, -10.5]
|
||||
"pivot": [0, 9.4, -10.7]
|
||||
},
|
||||
{
|
||||
"name": "head_correction",
|
||||
"parent": "head",
|
||||
"pivot": [0, 9.5, -10.5]
|
||||
"pivot": [0, 10, -11]
|
||||
},
|
||||
{
|
||||
"name": "head_ai",
|
||||
"parent": "head_correction",
|
||||
"pivot": [0, 9.5, -10.5]
|
||||
"pivot": [0, 10, -11]
|
||||
},
|
||||
{
|
||||
"name": "head_angle",
|
||||
@@ -99,6 +99,23 @@
|
||||
{"origin": [-4, 4.53407, -24.34461], "size": [8, 3, 8], "inflate": -0.01, "pivot": [0, 6.53407, -20.34461], "rotation": [0, -45, 0], "uv": [92, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 7, -22.25],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"jaw_lower": [0, 7, -22.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 7.5, -25.5],
|
||||
"locators": {
|
||||
"item": [0, 7.5, -25.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_ear",
|
||||
"parent": "head_angle",
|
||||
@@ -129,6 +146,17 @@
|
||||
{"origin": [0, 14.53407, -27.00146], "size": [0, 2, 2], "uv": [0, 44]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_horn",
|
||||
"parent": "horn",
|
||||
"pivot": [0, 17.5, -25.5],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"horn": [0, 17.5, -25.5],
|
||||
"physical": [0, 17.5, -25.5],
|
||||
"special": [0, 17.5, -25.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_tooth",
|
||||
"parent": "head_angle",
|
||||
@@ -169,6 +197,14 @@
|
||||
{"origin": [6.51, 10.03407, -23.25882], "size": [0, 1, 1], "inflate": 0.02, "pivot": [6.5, 10.53407, -20.75882], "rotation": [0, 45, 0], "uv": [2, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_eye_left",
|
||||
"parent": "left_pupil",
|
||||
"pivot": [5, 10.5, -22.25],
|
||||
"locators": {
|
||||
"eye3": [5, 10.5, -22.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_eyelid",
|
||||
"parent": "eyes",
|
||||
@@ -260,6 +296,71 @@
|
||||
{"origin": [-6.51, 10.03407, -23.25882], "size": [0, 1, 1], "inflate": 0.02, "pivot": [-6.5, 10.53407, -20.75882], "rotation": [0, -45, 0], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_eye_right",
|
||||
"parent": "right_pupil",
|
||||
"pivot": [-5, 10.5, -22.25],
|
||||
"locators": {
|
||||
"eye2": [-5, 10.5, -22.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_mouth",
|
||||
"parent": "head",
|
||||
"pivot": [0, 7, -17],
|
||||
"locators": {
|
||||
"mouth": [0, 7, -17]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "head",
|
||||
"pivot": [0, 7.75, -20.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"jaw_upper": [0, 7.75, -20.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_head",
|
||||
"parent": "head",
|
||||
"pivot": [0, 15, -19.25],
|
||||
"locators": {
|
||||
"head": [0, 15, -19.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_hat",
|
||||
"parent": "head",
|
||||
"pivot": [0, 16, -17.25],
|
||||
"locators": {
|
||||
"item_hat": [0, 16, -17.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_face",
|
||||
"parent": "head",
|
||||
"pivot": [0, 10.5, -27.25],
|
||||
"locators": {
|
||||
"face": [0, 10.5, -27.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_face",
|
||||
"parent": "head",
|
||||
"pivot": [0, 10.25, -27.25],
|
||||
"locators": {
|
||||
"item_face": [0, 10.25, -27.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_seat_1",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 19, -8],
|
||||
"locators": {
|
||||
"seat_1": [0, 19, -8]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_front_leg",
|
||||
"parent": "body",
|
||||
@@ -285,6 +386,15 @@
|
||||
{"origin": [9, 0, -11.5], "size": [0, 2, 2], "pivot": [9, 0, -9.5], "rotation": [0, -2.5, 0], "uv": [16, 36]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_primary2",
|
||||
"parent": "left_front_foot",
|
||||
"pivot": [7.5, 1, -7.1],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_primary2": [7.5, 1, -7.1]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "right_front_leg",
|
||||
"parent": "body",
|
||||
@@ -310,6 +420,15 @@
|
||||
{"origin": [-9, 0, -11.5], "size": [0, 2, 2], "pivot": [-9, 0, -9.5], "rotation": [0, 2.5, 0], "uv": [12, 34]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_primary1",
|
||||
"parent": "right_front_foot",
|
||||
"pivot": [-7.5, 1, -7.1],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_primary1": [-7.5, 1, -7.1]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_back_leg",
|
||||
"parent": "body",
|
||||
@@ -335,6 +454,15 @@
|
||||
{"origin": [8.5, 0, 2], "size": [0, 2, 2], "pivot": [8.5, 0, 4], "rotation": [0, -5, 0], "uv": [0, 36]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_secondary2",
|
||||
"parent": "left_back_foot",
|
||||
"pivot": [7.5, 1, 7.15],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_secondary2": [7.5, 1, 7.15]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "right_back_leg",
|
||||
"parent": "body",
|
||||
@@ -359,6 +487,47 @@
|
||||
{"origin": [-5.5, 0, 2], "size": [0, 2, 2], "pivot": [-5.5, 0, 4], "rotation": [0, -5, 0], "uv": [0, 8]},
|
||||
{"origin": [-8.5, 0, 2], "size": [0, 2, 2], "pivot": [-8.5, 0, 4], "rotation": [0, 5, 0], "uv": [0, 6]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_secondary",
|
||||
"parent": "right_back_foot",
|
||||
"pivot": [-7.5, 1, 7.15],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_secondary": [-7.5, 1, 7.15]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_middle",
|
||||
"parent": "body",
|
||||
"pivot": [0, 12, 0],
|
||||
"locators": {
|
||||
"middle": [0, 12, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_target",
|
||||
"parent": "body",
|
||||
"pivot": [0, 6.75, -31],
|
||||
"locators": {
|
||||
"target": [0, 6.75, -31]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_root",
|
||||
"parent": "rhyhorn",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
"root": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_top",
|
||||
"parent": "rhyhorn",
|
||||
"pivot": [0, 25.5, 0],
|
||||
"locators": {
|
||||
"top": [0, 25.5, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+204
-7
@@ -27,16 +27,20 @@
|
||||
"cubes": [
|
||||
{"origin": [-8.5, 4, -11], "size": [17, 15, 21], "uv": [0, 36]},
|
||||
{"origin": [-8.5, 4, -11], "size": [17, 15, 21], "inflate": 0.2, "uv": [0, 0]},
|
||||
{"origin": [8.75, 9.5, -9.5], "size": [0, 10, 14], "pivot": [8.75, 12.75, -9.5], "rotation": [15, 10, 2.5], "uv": [28, 58]},
|
||||
{"origin": [-8.75, 9.5, -9.5], "size": [0, 10, 14], "pivot": [-8.75, 12.75, -9.5], "rotation": [15, -10, -2.5], "uv": [0, 58]},
|
||||
{"origin": [8.75, 1.75, -10.5], "size": [0, 11, 11], "pivot": [8.75, 8.75, -9.5], "rotation": [17.5, 12.5, 5], "uv": [24, 83]},
|
||||
{"origin": [-8.75, 1.75, -10.5], "size": [0, 11, 11], "pivot": [-8.75, 8.75, -9.5], "rotation": [17.5, -12.5, -5], "uv": [80, 6]},
|
||||
{"origin": [9.25, 4, -1.75], "size": [0, 9, 14], "pivot": [9.225, -2.25, 0.25], "rotation": [2.5, 12.5, 2.5], "uv": [0, 68]},
|
||||
{"origin": [-9.25, 4, -1.75], "size": [0, 9, 14], "pivot": [-9.225, -2.25, 0.25], "rotation": [2.5, -12.5, -2.5], "uv": [56, 62]},
|
||||
{"origin": [9.5, 11, -0.5], "size": [0, 8, 12], "pivot": [9.95389, 15.17057, 1.69638], "rotation": [0, 5, -5], "uv": [80, 16]},
|
||||
{"origin": [-9.5, 11, -0.5], "size": [0, 8, 12], "pivot": [-9.95389, 15.17057, 1.69638], "rotation": [0, -5, 5], "uv": [0, 79]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_seat_1",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 19, -8],
|
||||
"locators": {
|
||||
"seat_1": [0, 19, -8]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spine",
|
||||
"parent": "torso",
|
||||
@@ -51,20 +55,52 @@
|
||||
{"origin": [0, 19.75, 5.75], "size": [0, 3, 3], "uv": [15, 5]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_bodyplate",
|
||||
"parent": "torso",
|
||||
"pivot": [8.75, 12.75, -9.5],
|
||||
"cubes": [
|
||||
{"origin": [8.75, 9.5, -9.5], "size": [0, 10, 14], "pivot": [8.75, 12.75, -9.5], "rotation": [15, 10, 2.5], "uv": [28, 58]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_bodyplate",
|
||||
"parent": "torso",
|
||||
"pivot": [-8.75, 12.75, -9.5],
|
||||
"cubes": [
|
||||
{"origin": [-8.75, 9.5, -9.5], "size": [0, 10, 14], "pivot": [-8.75, 12.75, -9.5], "rotation": [15, -10, -2.5], "uv": [0, 58]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "left_legplate",
|
||||
"parent": "torso",
|
||||
"pivot": [8.75, 8.75, -7.5],
|
||||
"cubes": [
|
||||
{"origin": [8.75, 1.75, -10.5], "size": [0, 11, 11], "pivot": [8.75, 8.75, -9.5], "rotation": [17.5, 12.5, 5], "uv": [24, 83]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "right_legplate",
|
||||
"parent": "torso",
|
||||
"pivot": [-8.75, 8.75, -7.5],
|
||||
"cubes": [
|
||||
{"origin": [-8.75, 1.75, -10.5], "size": [0, 11, 11], "pivot": [-8.75, 8.75, -9.5], "rotation": [17.5, -12.5, -5], "uv": [80, 6]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 9.5, -10.5]
|
||||
"pivot": [0, 9.4, -10.7]
|
||||
},
|
||||
{
|
||||
"name": "head_correction",
|
||||
"parent": "head",
|
||||
"pivot": [0, 9.5, -10.5]
|
||||
"pivot": [0, 10, -11]
|
||||
},
|
||||
{
|
||||
"name": "head_ai",
|
||||
"parent": "head_correction",
|
||||
"pivot": [0, 9.5, -10.5]
|
||||
"pivot": [0, 10, -11]
|
||||
},
|
||||
{
|
||||
"name": "head_angle",
|
||||
@@ -99,6 +135,23 @@
|
||||
{"origin": [-4, 4.53407, -24.34461], "size": [8, 3, 8], "inflate": -0.01, "pivot": [0, 6.53407, -20.34461], "rotation": [0, -45, 0], "uv": [92, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw_front",
|
||||
"pivot": [0, 7, -22.25],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"jaw_lower": [0, 7, -22.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item",
|
||||
"parent": "jaw_front",
|
||||
"pivot": [0, 7.5, -25.5],
|
||||
"locators": {
|
||||
"item": [0, 7.5, -25.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_ear",
|
||||
"parent": "head_angle",
|
||||
@@ -129,6 +182,17 @@
|
||||
{"origin": [0, 15.03407, -27.00146], "size": [0, 3, 2], "pivot": [0, 15.78407, -26.00146], "rotation": [-7.5, 0, 0], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_horn",
|
||||
"parent": "horn",
|
||||
"pivot": [0, 17.5, -25.5],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"horn": [0, 17.5, -25.5],
|
||||
"physical": [0, 17.5, -25.5],
|
||||
"special": [0, 17.5, -25.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_tooth",
|
||||
"parent": "head_angle",
|
||||
@@ -169,6 +233,14 @@
|
||||
{"origin": [6.51, 10.03407, -23.25882], "size": [0, 1, 1], "inflate": 0.02, "pivot": [6.5, 10.53407, -20.75882], "rotation": [0, 45, 0], "uv": [2, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_eye_left",
|
||||
"parent": "left_pupil",
|
||||
"pivot": [5, 10.5, -22.25],
|
||||
"locators": {
|
||||
"eye3": [5, 10.5, -22.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_eyelid",
|
||||
"parent": "eyes",
|
||||
@@ -260,6 +332,63 @@
|
||||
{"origin": [-6.51, 10.03407, -23.25882], "size": [0, 1, 1], "inflate": 0.02, "pivot": [-6.5, 10.53407, -20.75882], "rotation": [0, -45, 0], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_eye_right",
|
||||
"parent": "right_pupil",
|
||||
"pivot": [-5, 10.5, -22.25],
|
||||
"locators": {
|
||||
"eye2": [-5, 10.5, -22.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_mouth",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 7, -17],
|
||||
"locators": {
|
||||
"mouth": [0, 7, -17]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 7.75, -20.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"jaw_upper": [0, 7.75, -20.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_head",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 15, -19.25],
|
||||
"locators": {
|
||||
"head": [0, 15, -19.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_hat",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 16, -17.25],
|
||||
"locators": {
|
||||
"item_hat": [0, 16, -17.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_face",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 10.5, -27.25],
|
||||
"locators": {
|
||||
"face": [0, 10.5, -27.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_face",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 10.25, -27.25],
|
||||
"locators": {
|
||||
"item_face": [0, 10.25, -27.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_front_leg",
|
||||
"parent": "body",
|
||||
@@ -285,6 +414,15 @@
|
||||
{"origin": [9, 0, -11.5], "size": [0, 2, 2], "pivot": [9, 0, -9.5], "rotation": [0, -2.5, 0], "uv": [16, 36]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_primary2",
|
||||
"parent": "left_front_foot",
|
||||
"pivot": [7.5, 1, -7.1],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_primary2": [7.5, 1, -7.1]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "right_front_leg",
|
||||
"parent": "body",
|
||||
@@ -310,6 +448,15 @@
|
||||
{"origin": [-9, 0, -11.5], "size": [0, 2, 2], "pivot": [-9, 0, -9.5], "rotation": [0, 2.5, 0], "uv": [12, 34]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_primary1",
|
||||
"parent": "right_front_foot",
|
||||
"pivot": [-7.5, 1, -7.1],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_primary1": [-7.5, 1, -7.1]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_back_leg",
|
||||
"parent": "body",
|
||||
@@ -335,6 +482,15 @@
|
||||
{"origin": [8.5, 0, 2], "size": [0, 2, 2], "pivot": [8.5, 0, 4], "rotation": [0, -5, 0], "uv": [0, 36]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_secondary2",
|
||||
"parent": "left_back_foot",
|
||||
"pivot": [7.5, 1, 7.15],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_secondary2": [7.5, 1, 7.15]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "right_back_leg",
|
||||
"parent": "body",
|
||||
@@ -359,6 +515,47 @@
|
||||
{"origin": [-5.5, 0, 2], "size": [0, 2, 2], "pivot": [-5.5, 0, 4], "rotation": [0, -5, 0], "uv": [0, 8]},
|
||||
{"origin": [-8.5, 0, 2], "size": [0, 2, 2], "pivot": [-8.5, 0, 4], "rotation": [0, 5, 0], "uv": [0, 6]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_secondary",
|
||||
"parent": "right_back_foot",
|
||||
"pivot": [-7.5, 1, 7.15],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_secondary": [-7.5, 1, 7.15]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_middle",
|
||||
"parent": "body",
|
||||
"pivot": [0, 12, 0],
|
||||
"locators": {
|
||||
"middle": [0, 12, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_target",
|
||||
"parent": "body",
|
||||
"pivot": [0, 6.75, -31],
|
||||
"locators": {
|
||||
"target": [0, 6.75, -31]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_root",
|
||||
"parent": "rhyhorn",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
"root": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_top",
|
||||
"parent": "rhyhorn",
|
||||
"pivot": [0, 25.5, 0],
|
||||
"locators": {
|
||||
"top": [0, 25.5, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+189
-3
@@ -90,6 +90,15 @@
|
||||
{"origin": [24.5, 21, 1.5], "size": [2, 1, 1], "uv": [59, 37]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_hand_secondary",
|
||||
"parent": "left_lower_arm",
|
||||
"pivot": [23.75, 22, 0],
|
||||
"rotation": [0, -90, 0],
|
||||
"locators": {
|
||||
"hand_secondary": [23.75, 22, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "right_shoulder",
|
||||
"parent": "upper_torso",
|
||||
@@ -141,6 +150,23 @@
|
||||
{"origin": [-26.5, 21, 1.5], "size": [2, 1, 1], "uv": [9, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_item",
|
||||
"parent": "right_lower_arm",
|
||||
"pivot": [-24.75, 22, 0],
|
||||
"locators": {
|
||||
"item": [-24.75, 22, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_hand_primary",
|
||||
"parent": "right_lower_arm",
|
||||
"pivot": [-23.75, 22, 0],
|
||||
"rotation": [0, 90, 0],
|
||||
"locators": {
|
||||
"hand_primary": [-23.75, 22, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "backspike2",
|
||||
"parent": "upper_torso",
|
||||
@@ -160,17 +186,17 @@
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "upper_torso",
|
||||
"pivot": [0, 25.75, 0.5]
|
||||
"pivot": [0, 26, 0]
|
||||
},
|
||||
{
|
||||
"name": "head_correction",
|
||||
"parent": "head",
|
||||
"pivot": [0, 25.75, 0.5]
|
||||
"pivot": [0, 26, 0]
|
||||
},
|
||||
{
|
||||
"name": "head_ai",
|
||||
"parent": "head_correction",
|
||||
"pivot": [0, 25.75, 0.5]
|
||||
"pivot": [0, 26, 0]
|
||||
},
|
||||
{
|
||||
"name": "head_angle",
|
||||
@@ -202,6 +228,15 @@
|
||||
{"origin": [-3.5, 25, -12.5], "size": [7, 3, 3], "uv": [0, 70]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 28, -9.75],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"jaw2": [0, 28, -9.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eyes",
|
||||
"parent": "head_angle",
|
||||
@@ -224,6 +259,14 @@
|
||||
{"origin": [6, 30.75, -10], "size": [0, 1, 1], "inflate": 0.02, "uv": [0, 1]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_eye_left",
|
||||
"parent": "left_pupil",
|
||||
"pivot": [6, 31.25, -9.5],
|
||||
"locators": {
|
||||
"eye_left": [6, 31.25, -9.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_eyelid",
|
||||
"parent": "eyes",
|
||||
@@ -317,6 +360,14 @@
|
||||
{"origin": [-6, 30.75, -10], "size": [0, 1, 1], "inflate": 0.02, "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_eye_right",
|
||||
"parent": "right_pupil",
|
||||
"pivot": [-6, 31.25, -9.5],
|
||||
"locators": {
|
||||
"eye_right": [-6, 31.25, -9.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "left_ear",
|
||||
"parent": "head_angle",
|
||||
@@ -351,6 +402,16 @@
|
||||
{"origin": [-2, 31.68934, -14.07538], "size": [4, 4, 4], "uv": [100, 100]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_horn",
|
||||
"parent": "horn_rotation",
|
||||
"pivot": [0, 33.675, -20],
|
||||
"locators": {
|
||||
"horn": [0, 33.675, -20],
|
||||
"special": [0, 33.675, -20],
|
||||
"physical": [0, 33.675, -20]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "backspike4",
|
||||
"parent": "head_angle",
|
||||
@@ -359,6 +420,63 @@
|
||||
{"origin": [0, 26.5, 1.5], "size": [0, 5, 6], "pivot": [0, 31, 2.25], "rotation": [30, 0, 0], "uv": [0, 29]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 28.25, -7.75],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"jaw1": [0, 28.25, -7.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_head",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 36, -7.5],
|
||||
"locators": {
|
||||
"head": [0, 36, -7.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_hat",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 36, -5],
|
||||
"locators": {
|
||||
"item_hat": [0, 36, -5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_face",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 31, -13.5],
|
||||
"locators": {
|
||||
"face": [0, 31, -13.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_face",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 30.75, -13.5],
|
||||
"locators": {
|
||||
"item_face": [0, 30.75, -13.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_mouth",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 27.5, -5.75],
|
||||
"locators": {
|
||||
"mouth": [0, 27.5, -5.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_seat_1",
|
||||
"parent": "upper_torso",
|
||||
"pivot": [0, 26.25, 9],
|
||||
"locators": {
|
||||
"seat_1": [0, 26.25, 9]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tail",
|
||||
"parent": "torso",
|
||||
@@ -392,6 +510,24 @@
|
||||
{"origin": [-2, 5.25, 28.5], "size": [4, 4, 9], "uv": [89, 87]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_tail_tip",
|
||||
"parent": "tail4",
|
||||
"pivot": [0, 7.25, 37.5],
|
||||
"rotation": [0, 180, 0],
|
||||
"locators": {
|
||||
"tail_tip": [0, 7.25, 37.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_tail",
|
||||
"parent": "tail3",
|
||||
"pivot": [0, 7.25, 25],
|
||||
"rotation": [0, 180, 0],
|
||||
"locators": {
|
||||
"tail": [0, 7.25, 25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "backspike",
|
||||
"parent": "torso",
|
||||
@@ -436,6 +572,15 @@
|
||||
{"origin": [10, -0.25, -13], "size": [2, 2, 3], "pivot": [10, 0.75, -10], "rotation": [0, -5, 0], "uv": [29, 78]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_secondary",
|
||||
"parent": "left_foot",
|
||||
"pivot": [9, 1, -5.75],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_secondary": [9, 1, -5.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "right_upper_leg",
|
||||
"parent": "body",
|
||||
@@ -471,6 +616,47 @@
|
||||
{"origin": [-8, -0.25, -13], "size": [2, 2, 3], "pivot": [-8, 0.75, -10], "rotation": [0, -5, 0], "uv": [77, 0]},
|
||||
{"origin": [-12, -0.25, -13], "size": [2, 2, 3], "pivot": [-10, 0.75, -10], "rotation": [0, 5, 0], "uv": [26, 57]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_foot_primary",
|
||||
"parent": "right_foot",
|
||||
"pivot": [-9, 1, -5.75],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_primary": [-9, 1, -5.75]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_middle",
|
||||
"parent": "body",
|
||||
"pivot": [0, 17, -2],
|
||||
"locators": {
|
||||
"middle": [0, 17, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_target",
|
||||
"parent": "body",
|
||||
"pivot": [0, 17, -16],
|
||||
"locators": {
|
||||
"target": [0, 17, -16]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_top",
|
||||
"parent": "rhydon",
|
||||
"pivot": [0, 38, 0],
|
||||
"locators": {
|
||||
"top": [0, 38, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_root",
|
||||
"parent": "rhydon",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
"root": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user