mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-11-01 22:08:52 -05: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 |
No files matched your search
@@ -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,11 +57,9 @@ 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")
|
||||
val RECENT_CATCH_ATTEMPT = register<UUID>("recent_catch_attempt")
|
||||
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,7 @@ interface TaskConfig {
|
||||
cobblemonResource("switch_to_panic_when_hostiles_nearby") to SwitchToPanicWhenHostilesNearbyTaskConfig::class.java,
|
||||
cobblemonResource("calm_down") to CalmDownTaskConfig::class.java,
|
||||
cobblemonResource("walk_away_from_avoid_target") to WalkAwayFromAvoidTargetTaskConfig::class.java,
|
||||
cobblemonResource("flee_nearest_hostile") to FleeNearestHostileTaskConfig::class.java,
|
||||
cobblemonResource("flee_attacker") to FleeAttackerTaskConfig::class.java,
|
||||
cobblemonResource("fly_in_circles") to FlyInCirclesTaskConfig::class.java,
|
||||
cobblemonResource("run_script") to RunScript::class.java,
|
||||
@@ -119,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
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
createDefault("great_ball", MultiplierModifier(1.5F))
|
||||
createDefault("ultra_ball", MultiplierModifier(2F))
|
||||
createDefault("master_ball", GuaranteedModifier())
|
||||
createDefault("safari_ball", CatchRateModifiers.SAFARI, stealthFactor = 0.75f)
|
||||
createDefault("safari_ball", CatchRateModifiers.SAFARI)
|
||||
createDefault("fast_ball", BaseStatModifier(Stats.SPEED, { it >= 100 }, 4F))
|
||||
createDefault("level_ball", CatchRateModifiers.LEVEL)
|
||||
createDefault("lure_ball", CatchRateModifiers.LURE)
|
||||
@@ -237,12 +237,11 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
model2d: ResourceLocation = cobblemonResource(name),
|
||||
model3d: ResourceLocation = cobblemonResource("item/${name}_model"),
|
||||
throwPower: Float = 1.25f,
|
||||
ancient: Boolean = false,
|
||||
stealthFactor: Float = 0.0f,
|
||||
ancient: Boolean = false
|
||||
): PokeBall {
|
||||
val identifier = cobblemonResource(name)
|
||||
//val finalModifiers = if (appendUltraBeastPenalty) modifiers + listOf(LabelModifier(0.1F, true, CobblemonPokemonLabels.ULTRA_BEAST)) else modifiers
|
||||
val pokeball = PokeBall(identifier, modifier, effects, waterDragValue, model2d, model3d, throwPower, ancient, stealthFactor)
|
||||
val pokeball = PokeBall(identifier, modifier, effects, waterDragValue, model2d, model3d, throwPower, ancient)
|
||||
this.defaults[identifier] = pokeball
|
||||
return pokeball
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,9 @@ object BattleRegistry {
|
||||
.registerTypeAdapter(ShowdownMoveset::class.java, ShowdownMovesetAdapter)
|
||||
.create()
|
||||
private val battleMap = ConcurrentHashMap<UUID, PokemonBattle>()
|
||||
private val battleLock = ConcurrentHashMap<UUID, Boolean>()
|
||||
|
||||
fun onServerStarted() {
|
||||
battleMap.clear()
|
||||
battleLock.clear()
|
||||
}
|
||||
|
||||
fun onPlayerDisconnect(player: ServerPlayer) {
|
||||
@@ -207,18 +205,12 @@ object BattleRegistry {
|
||||
startShowdown(battle)
|
||||
}
|
||||
|
||||
if (!canPreempt) start().also {
|
||||
side1.actors.forEach { actor -> battleLock.remove(actor.uuid) }
|
||||
side2.actors.forEach { actor -> battleLock.remove(actor.uuid) }
|
||||
return SuccessfulBattleStart(battle)
|
||||
}
|
||||
if (!canPreempt) start().also { return SuccessfulBattleStart(battle) }
|
||||
|
||||
val preBattleEvent = BattleStartedEvent.Pre(battle)
|
||||
CobblemonEvents.BATTLE_STARTED_PRE.postThen(preBattleEvent) {
|
||||
start()
|
||||
CobblemonEvents.BATTLE_STARTED_POST.post(BattleStartedEvent.Post(battle))
|
||||
side1.actors.forEach { actor -> battleLock.remove(actor.uuid) }
|
||||
side2.actors.forEach { actor -> battleLock.remove(actor.uuid) }
|
||||
return SuccessfulBattleStart(battle)
|
||||
}
|
||||
return ErroredBattleStart(mutableSetOf(BattleStartError.canceledByEvent(preBattleEvent.reason)))
|
||||
@@ -237,19 +229,6 @@ object BattleRegistry {
|
||||
return battleMap.values.find { it.getActor(serverPlayer) != null }
|
||||
}
|
||||
|
||||
fun checkBattleLock(serverPlayer: ServerPlayer, ancientIsOkay: Boolean): Boolean =
|
||||
if (ancientIsOkay)
|
||||
battleLock.get(serverPlayer.uuid) == false
|
||||
else
|
||||
battleLock.containsKey(serverPlayer.uuid)
|
||||
|
||||
fun lockPlayer(serverPlayer: ServerPlayer, ancient: Boolean) {
|
||||
battleLock.put(serverPlayer.uuid, ancient)
|
||||
}
|
||||
fun unlockPlayer(serverPlayer: ServerPlayer) {
|
||||
battleLock.remove(serverPlayer.uuid)
|
||||
}
|
||||
|
||||
fun getBattleByParticipatingPlayerId(playerId: UUID): PokemonBattle? {
|
||||
return battleMap.values.find { playerId in it.playerUUIDs }
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@ class ForcePassActionResponse : ShowdownActionResponse(ShowdownActionResponseTyp
|
||||
return false
|
||||
}
|
||||
|
||||
return activeBattlePokemon.actor.expectingPassActions.isNotEmpty()
|
||||
return activeBattlePokemon.actor.expectingPassActions.size > 0
|
||||
}
|
||||
|
||||
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?) = "pass"
|
||||
|
||||
@@ -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
|
||||
|
||||
+31
-102
@@ -13,9 +13,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonEntities.EMPTY_POKEBALL
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.pokeball.PokeBallCaptureCalculatedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokeball.ThrownPokeballHitEvent
|
||||
@@ -30,10 +28,8 @@ import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
||||
import com.cobblemon.mod.common.api.text.green
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.BattleBuilder
|
||||
import com.cobblemon.mod.common.battles.BattleCaptureAction
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.BattleTypes
|
||||
@@ -76,6 +72,7 @@ import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.EntityHitResult
|
||||
import net.minecraft.world.phys.HitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
@@ -107,8 +104,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
|
||||
override val schedulingTracker = SchedulingTracker()
|
||||
var capturingPokemon: PokemonEntity? = null
|
||||
var captureFuture = CompletableFuture<Boolean>()
|
||||
var capturePostAction: (Boolean) -> Unit = {}
|
||||
val captureFuture = CompletableFuture<Boolean>()
|
||||
var captureState: CaptureState
|
||||
get() = CaptureState.entries[entityData.get(CAPTURE_STATE).toInt()]
|
||||
set(value) { entityData.set(CAPTURE_STATE, value.ordinal.toByte()) }
|
||||
@@ -183,28 +179,20 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
var pokeBall: PokeBall = PokeBalls.POKE_BALL
|
||||
|
||||
override fun onHitBlock(hitResult: BlockHitResult) {
|
||||
when (captureState) {
|
||||
CaptureState.FALL -> {
|
||||
if (level().isServerSide()) {
|
||||
beginCapture()
|
||||
if (captureState == CaptureState.NOT) {
|
||||
if (level().isServerSide()) {
|
||||
super.onHitBlock(hitResult)
|
||||
level().sendParticlesServer(ParticleTypes.CLOUD, hitResult.location, 2, hitResult.location.subtract(position()).normalize().scale(-0.1), 0.0)
|
||||
level().playSoundServer(position(), SoundEvents.WOOD_PLACE, pitch = 2.5F)
|
||||
discard()
|
||||
val player = this.owner as? ServerPlayer
|
||||
if (player?.isCreative == false) {
|
||||
spawnAtLocation(defaultItem)
|
||||
}
|
||||
}
|
||||
CaptureState.NOT -> {
|
||||
if (level().isServerSide()) {
|
||||
super.onHitBlock(hitResult)
|
||||
level().sendParticlesServer(ParticleTypes.CLOUD, hitResult.location, 2, hitResult.location.subtract(position()).normalize().scale(-0.1), 0.0)
|
||||
level().playSoundServer(position(), SoundEvents.WOOD_PLACE, pitch = 2.5F)
|
||||
discard()
|
||||
val player = this.owner as? ServerPlayer
|
||||
if (player?.isCreative == false) {
|
||||
spawnAtLocation(defaultItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
isNoGravity = false
|
||||
deltaMovement = Vec3.ZERO
|
||||
}
|
||||
} else {
|
||||
setNoGravity(false)
|
||||
deltaMovement = Vec3.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,13 +255,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
owner?.sendSystemMessage(lang("capture.busy", pokemonEntity.exposedSpecies.translatedName).red())
|
||||
return drop()
|
||||
} else if (owner is ServerPlayer && BattleRegistry.getBattleByParticipatingPlayer(owner) != null) {
|
||||
owner.sendSystemMessage(lang("capture.you_in_battle").red())
|
||||
return drop()
|
||||
} else if (owner is ServerPlayer && BattleRegistry.checkBattleLock(owner, pokeBall.ancient)) {
|
||||
owner.sendSystemMessage(lang("capture.you_already_capturing").red())
|
||||
return drop()
|
||||
} else if (pokemonEntity.brain.hasMemoryValue(CobblemonMemories.RECENT_CATCH_ATTEMPT)) {
|
||||
owner?.sendSystemMessage(lang("capture.enraged", pokemonEntity.exposedSpecies.translatedName).red())
|
||||
owner.sendSystemMessage(lang("you_in_battle").red())
|
||||
return drop()
|
||||
}
|
||||
|
||||
@@ -297,29 +279,6 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
super.onHitEntity(hitResult)
|
||||
}
|
||||
|
||||
private fun inBattleCatchAction(battle: PokemonBattle, thrower: LivingEntity, pokemonEntity: PokemonEntity) {
|
||||
val throwerActor = battle.getActor(thrower.uuid)
|
||||
val hitActor = battle.actors.find { it.isForPokemon(pokemonEntity) }
|
||||
val hitBattlePokemon = hitActor?.activePokemon?.find { it.battlePokemon?.effectedPokemon?.entity == pokemonEntity }
|
||||
|
||||
if (throwerActor == null || hitActor == null || hitBattlePokemon == null) {
|
||||
return // Weird, shouldn't be possible
|
||||
}
|
||||
|
||||
val pokemonName = hitBattlePokemon.battlePokemon?.getName() ?: "error".red()
|
||||
|
||||
battle.broadcastChatMessage(
|
||||
lang(
|
||||
"capture.attempted_capture",
|
||||
throwerActor.getName(),
|
||||
pokeBall.item().description,
|
||||
pokemonName
|
||||
).yellow()
|
||||
)
|
||||
battle.dispatchWaiting(2F) { battle.broadcastChatMessage(lang("capture.broke_free", pokemonName).red()) }
|
||||
battle.dispatchGo { throwerActor.forceChoose(ForcePassActionResponse()) }
|
||||
}
|
||||
|
||||
private fun drop() {
|
||||
val owner = owner
|
||||
discard()
|
||||
@@ -393,11 +352,6 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
if (pokemon.pokemon.isWild() && pokemon.isAlive && !captureFuture.isDone) {
|
||||
pokemon.discard()
|
||||
discard()
|
||||
capturePostAction(true)
|
||||
val owner = owner
|
||||
if (owner != null && owner is ServerPlayer) {
|
||||
BattleRegistry.unlockPlayer(owner)
|
||||
}
|
||||
captureFuture.complete(true)
|
||||
val party = player.party()
|
||||
pokemon.pokemon.caughtBall = pokeBall
|
||||
@@ -465,11 +419,6 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
after(seconds = 0.1F) {
|
||||
pokemon.beamMode = 0
|
||||
pokemon.busyLocks.remove(this)
|
||||
capturePostAction(false)
|
||||
val owner = owner
|
||||
if (owner != null && owner is ServerPlayer) {
|
||||
BattleRegistry.unlockPlayer(owner)
|
||||
}
|
||||
captureFuture.complete(false)
|
||||
val ballType =
|
||||
this.pokeBall.name.path.lowercase().replace("_", "")
|
||||
@@ -493,10 +442,6 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
|
||||
private fun attemptCatch(pokemonEntity: PokemonEntity) {
|
||||
pokemonEntity.busyLocks.add(this)
|
||||
val owner = owner
|
||||
if (owner != null && owner is ServerPlayer) {
|
||||
BattleRegistry.lockPlayer(owner, pokeBall.ancient)
|
||||
}
|
||||
val displace = deltaMovement
|
||||
captureState = CaptureState.HIT
|
||||
val mul = if (random.nextBoolean()) 1 else -1
|
||||
@@ -511,7 +456,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
after(seconds = 0.7F) {
|
||||
// Start beaming them up.
|
||||
deltaMovement = Vec3.ZERO
|
||||
isNoGravity = true
|
||||
setNoGravity(true)
|
||||
level().playSoundServer(position(), CobblemonSounds.POKE_BALL_RECALL, volume = 0.6F)
|
||||
pokemonEntity.beamMode = 3
|
||||
}
|
||||
@@ -526,7 +471,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
// If it was still falling after a second and a half, just assume it's landed because we can't wait all day.
|
||||
if (captureState == CaptureState.FALL) {
|
||||
deltaMovement = Vec3.ZERO
|
||||
isNoGravity = true
|
||||
setNoGravity(true)
|
||||
setOnGround(true)
|
||||
beginCapture()
|
||||
}
|
||||
@@ -534,40 +479,25 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
}
|
||||
}
|
||||
|
||||
// We have hit the ground, time to stop falling and start shaking! Calculate capture.
|
||||
fun beginCapture() {
|
||||
val capturingPokemon = this.capturingPokemon ?: return
|
||||
capturingPokemon.setPositionSafely(position())
|
||||
override fun onHit(hitResult: HitResult) {
|
||||
super.onHit(hitResult)
|
||||
if (captureState == CaptureState.FALL && hitResult.type == HitResult.Type.BLOCK) {
|
||||
if (level().isServerSide()) {
|
||||
beginCapture()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun beginCapture() {
|
||||
// We have hit the ground, time to stop falling and start shaking! Calculate capture.
|
||||
capturingPokemon?.setPositionSafely(position())
|
||||
val thrower = owner as LivingEntity
|
||||
val captureResult = Cobblemon.config.captureCalculator.processCapture(thrower, this, capturingPokemon).let {
|
||||
val event = PokeBallCaptureCalculatedEvent(thrower = thrower, pokemonEntity = capturingPokemon, pokeBallEntity = this, captureResult = it)
|
||||
val captureResult = Cobblemon.config.captureCalculator.processCapture(thrower, this, capturingPokemon!!).let {
|
||||
val event = PokeBallCaptureCalculatedEvent(thrower = thrower, pokemonEntity = capturingPokemon!!, pokeBallEntity = this, captureResult = it)
|
||||
CobblemonEvents.POKE_BALL_CAPTURE_CALCULATED.post(event)
|
||||
event.captureResult
|
||||
}
|
||||
|
||||
if (thrower is ServerPlayer) {
|
||||
val battle = (capturingPokemon.delegate as PokemonServerDelegate).getBattle()
|
||||
if (battle == null && !pokeBall.ancient) {
|
||||
capturingPokemon.brain.setMemoryWithExpiry(CobblemonMemories.RECENT_CATCH_ATTEMPT, thrower.uuid, 30 * 20)
|
||||
this.capturePostAction = {
|
||||
if (!it) {
|
||||
if (this.pokeBall.stealthFactor > 0.0f && this.random.nextFloat() < this.pokeBall.stealthFactor) {
|
||||
thrower.sendSystemMessage(lang("capture.didnt_notice", capturingPokemon.exposedSpecies.translatedName).green())
|
||||
} else {
|
||||
thrower.sendSystemMessage(lang("capture.got_enraged", capturingPokemon.exposedSpecies.translatedName).red())
|
||||
val lead = thrower.party().firstOrNull {it.entity != null}?.uuid
|
||||
if (lead != null) {
|
||||
BattleBuilder.pve(thrower, capturingPokemon, lead).ifSuccessful { battle ->
|
||||
inBattleCatchAction(battle, thrower, capturingPokemon)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var rollsRemaining = captureResult.numberOfShakes
|
||||
if (rollsRemaining == 4) {
|
||||
rollsRemaining--
|
||||
@@ -600,12 +530,11 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun getCurrentPoseType(): PoseType {
|
||||
return PoseType.NONE
|
||||
}
|
||||
|
||||
override fun canUsePortal(allowVehicles: Boolean) = captureState == CaptureState.NOT
|
||||
override fun canUsePortal(allowVehicles: Boolean) = false
|
||||
|
||||
override fun getAddEntityPacket(entityTrackerEntry: ServerEntity): Packet<ClientGamePacketListener> =
|
||||
ClientboundCustomPayloadPacket(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,15 +40,13 @@ open class PokeBall(
|
||||
val model2d: ResourceLocation,
|
||||
val model3d: ResourceLocation,
|
||||
val throwPower: Float,
|
||||
val ancient: Boolean,
|
||||
val stealthFactor: Float,
|
||||
val ancient: Boolean
|
||||
) {
|
||||
val struct = QueryStruct(hashMapOf())
|
||||
.addFunction("name") { StringValue(name.toString()) }
|
||||
.addFunction("water_drag_value") { DoubleValue(waterDragValue) }
|
||||
.addFunction("throw_power") { DoubleValue(throwPower) }
|
||||
.addFunction("is_ancient") { DoubleValue(ancient) }
|
||||
.addFunction("stealth_factor") { DoubleValue(stealthFactor) }
|
||||
// .addFunction("item") { } // requires a registry which is hard
|
||||
|
||||
// This gets attached during item registry
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -296,7 +296,9 @@ object PokemonBrain {
|
||||
|
||||
fun onCaptureFailed(pokemonEntity: PokemonEntity, capturer: Entity) {
|
||||
if (pokemonEntity.pokemon.isWild() && pokemonEntity.battleId == null && capturer is LivingEntity) {
|
||||
pokemonEntity.brain.eraseMemory(MemoryModuleType.ATTACK_TARGET)
|
||||
pokemonEntity.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
pokemonEntity.getBrain().setMemoryWithExpiry(MemoryModuleType.AVOID_TARGET, capturer, AVOID_MEMORY_DURATION.sample(pokemonEntity.random).toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
+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
Loaded 100 of 374 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user