mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78dfb30759 |
@@ -34,7 +34,6 @@
|
||||
- Added Hyper Training items (IV Modification) as well as some additional candy items to do so (Health Candy, Sickly Candy)
|
||||
- Added Galarica Nut Bushes
|
||||
- Many Pokémon (mostly cats) are now feared by phantoms
|
||||
- Combees are now capable of gathering nectar from flowers and delivering it to either Saccharine leaves or hives. (Hive interactions are restricted to wild Combees)
|
||||
- Lightning is now affected by a Pokemon's ability/typing
|
||||
- Pokémon with the ability Lightning Rod draw in lightning similar to a lightning rod block albeit with a lower priority and range, gain immunity to lightning damage, and receive a temporary damage buff.
|
||||
- Pokémon with the ability Motor Drive are immune to lightning damage and receive a temporary speed buff when struck by lightning
|
||||
@@ -294,7 +293,6 @@
|
||||
- Tauros - Paldea Blaze
|
||||
- Tauros - Paldea Combat
|
||||
- Dewgong
|
||||
- Exeggutor - Kanto
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Cleffa
|
||||
@@ -405,9 +403,6 @@
|
||||
- Revavroom
|
||||
- Nickit
|
||||
- Thievul
|
||||
- Litwick
|
||||
- Lampent
|
||||
- Chandelure
|
||||
|
||||
### Changes
|
||||
- Changed pokemon caught and seen count to update based on the current pokedex being looked
|
||||
@@ -472,7 +467,6 @@
|
||||
- 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
|
||||
- Shulker Boxes and Traveler's Backpacks can no longer be held by Pokémon. Thanks Monocle ;) You could re-enable this with a datapack but you'd be crazy.
|
||||
|
||||
### Fixes
|
||||
- Fixed game crashing when removing national pokedex using datapacks
|
||||
@@ -996,7 +990,6 @@ Added new/updated particles for the following moves:
|
||||
- Parametric particle motion now works.
|
||||
- Event-spawned particles now work.
|
||||
- Particles can now have independent coordinate spaces.
|
||||
- Fixed suffocation of Pokémon when a pokeball breaks near a wall
|
||||
|
||||
### Developer
|
||||
- Updated the Pokédex data updated events to always include a `Pokemon` instance, and optionally a `DisguiseData` instance.
|
||||
|
||||
@@ -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.duck;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface RidePassenger {
|
||||
void cobblemon$setRideXRot(float rideXRot);
|
||||
float cobblemon$getRideXRot();
|
||||
void cobblemon$setRideYRot(float rideYRot);
|
||||
float cobblemon$getRideYRot();
|
||||
void cobblemon$setRideEyePos(Vec3 rideEyePos);
|
||||
Vec3 cobblemon$getRideEyePos();
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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;
|
||||
|
||||
@Mixin(AbstractArrow.class)
|
||||
public abstract class AbstractArrowMixin {
|
||||
|
||||
// Target the constructor that takes a LivingEntity owner
|
||||
@Inject(
|
||||
method = "<init>(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)V",
|
||||
at = @At("TAIL") // Inject at the very end of the constructor
|
||||
)
|
||||
private void cobblemon$adjustSpawnPosition(
|
||||
EntityType<? extends AbstractArrow> entityType,
|
||||
LivingEntity owner,
|
||||
Level level,
|
||||
ItemStack pickupItemStack,
|
||||
@Nullable ItemStack firedFromWeapon,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
AbstractArrow arrow = (AbstractArrow)(Object)this;
|
||||
if(!(owner.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
|
||||
// If this is a rolling ride passenger then use the rider eye position to set the arrow spawn position.
|
||||
if (owner instanceof RidePassenger ridePassenger && vehicleController != null && vehicleController.getActive()) {
|
||||
var eyePos = ridePassenger.cobblemon$getRideEyePos().add(0.0, -2.0, 0.0);
|
||||
arrow.setPos(eyePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +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.mixin;
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories;
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.Occupant.class)
|
||||
public abstract class BeeOccupantMixin {
|
||||
|
||||
@Inject(method = "createEntity", at = @At("RETURN"), cancellable = true)
|
||||
private void cobblemon$createEntity(Level level, BlockPos pos, CallbackInfoReturnable<Entity> cir) {
|
||||
// Needing to replicate all the post op stuff on the hive isn't great
|
||||
if (cir.getReturnValue() == null) {
|
||||
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
|
||||
CompoundTag compoundTag = occupant.entityData().copyTag();
|
||||
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
var state = level.getBlockState(pos);
|
||||
var newPos = Vec3.ZERO;
|
||||
var newYaw = 0f;
|
||||
var brain = pokemonEntity.getBrain();
|
||||
if (state.is(BlockTags.BEEHIVES)) {
|
||||
// position in front of the entrance, face away from the block
|
||||
var facing = state.getValue(HorizontalDirectionalBlock.FACING);
|
||||
newPos = pos.relative(facing).getCenter();
|
||||
newYaw = facing.toYRot();
|
||||
brain.setMemory(CobblemonMemories.INSTANCE.getHIVE_LOCATION(), pos); // This needs to be set in the case that the hive was picked up and moved.
|
||||
} else {
|
||||
// Block has likely been destroyed
|
||||
var center = pos.getCenter();
|
||||
newPos = new Vec3(
|
||||
center.x + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.y + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.z + level.random.nextFloat() * 0.6 - 0.3
|
||||
);
|
||||
newYaw = level.random.nextFloat() * 360F;
|
||||
brain.eraseMemory(CobblemonMemories.INSTANCE.getHIVE_LOCATION());
|
||||
}
|
||||
entity.yRotO = newYaw;
|
||||
entity.setPos(newPos);
|
||||
// Do honey logic
|
||||
var hasNectar = brain.getMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR()).orElse(false);
|
||||
if (hasNectar) {
|
||||
// Remove nectar and reset got to hive cooldown
|
||||
brain.eraseMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR());
|
||||
brain.setMemoryWithExpiry(CobblemonMemories.INSTANCE.getHIVE_COOLDOWN(), true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
|
||||
// Increment honey level of the hive
|
||||
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
|
||||
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
|
||||
if (i < 5) {
|
||||
int j = level.random.nextInt(100) == 0 ? 2 : 1;
|
||||
if (i + j > 5) {
|
||||
--j;
|
||||
}
|
||||
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
cir.setReturnValue(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
entity.save(compoundTag);
|
||||
Boolean hasNectar = pokemonEntity.getBrain().getMemory(CobblemonMemories.INSTANCE.getHAS_NECTAR()).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.mixin;
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeeDataAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeehiveBlockEntityAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BlockEntityAccessor;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public abstract class BeehiveBlockEntityMixin {
|
||||
|
||||
|
||||
// Accessor for the private 'stored' field in BeehiveBlockEntity
|
||||
@Accessor("stored")
|
||||
public abstract List<BeeDataAccessor> getStored();
|
||||
|
||||
@Inject(method = "emptyAllLivingFromHive", at = @At("HEAD"))
|
||||
private void cobblemon$emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, CallbackInfo ci) {
|
||||
if (player != null) {
|
||||
final BeehiveBlockEntity blockEntity = (BeehiveBlockEntity) (Object) this;
|
||||
// if the block is sedated or the player is too far away, no aggro should be applied
|
||||
if (blockEntity.isSedated() || player.position().distanceToSqr(blockEntity.getBlockPos().getCenter()) > 16.0)
|
||||
return;
|
||||
// from this point need to access private members of the block entity
|
||||
final BeehiveBlockEntityAccessor blockEntityAccessor = (BeehiveBlockEntityAccessor) this;
|
||||
List<Object> storedList = blockEntityAccessor.getStored();
|
||||
|
||||
List<Entity> list = Lists.newArrayList();
|
||||
storedList.removeIf((beeData) -> {
|
||||
BeehiveBlockEntity.Occupant occupant = ((BeeDataAccessor) beeData).invokeToOccupant();
|
||||
// Checking the for the tag allows us to make sure it's one of our pokemon before trying to rehydrate it into an entity
|
||||
boolean isPokemon = false;
|
||||
if (occupant.entityData().contains("id")) {
|
||||
isPokemon = "cobblemon:pokemon".equals(occupant.entityData().getUnsafe().getString("id"));
|
||||
}
|
||||
if (isPokemon) {
|
||||
return BeehiveBlockEntityAccessor.releaseOccupant(
|
||||
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
|
||||
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
|
||||
state,
|
||||
occupant,
|
||||
list,
|
||||
releaseStatus,
|
||||
blockEntityAccessor.savedFlowerPos());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
for (Entity entity : list) {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
((PokemonEntity) entity).getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "releaseOccupant",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"
|
||||
)
|
||||
)
|
||||
private static boolean cobblemon$captureReleasedEntity(
|
||||
Level level, Entity entity,
|
||||
Level lvl, BlockPos pos, BlockState state,
|
||||
BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> bees,
|
||||
BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos flowerPos) {
|
||||
|
||||
if (bees != null && !bees.contains(entity)) {
|
||||
// Avoid duplicates if vanilla also adds bees to the list on your version
|
||||
bees.add(entity);
|
||||
}
|
||||
return level.addFreshEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,23 +8,18 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
@@ -37,7 +32,6 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class LivingEntityMixin extends Entity implements OrientationControllable {
|
||||
@@ -53,12 +47,6 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
return cobblemon$orientationController;
|
||||
}
|
||||
|
||||
@Inject(method = "baseTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void cobblemon$updateRotationMatrix(CallbackInfo ci) {
|
||||
if (!cobblemon$orientationController.isActive() || cobblemon$orientationController.getOrientation() == null) return;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(this.getId(), cobblemon$orientationController.getOrientation()));
|
||||
}
|
||||
|
||||
@Inject(method = "onEffectRemoved", at = @At(value = "TAIL"))
|
||||
private void cobblemon$onEffectRemoved(MobEffectInstance effect, CallbackInfo ci) {
|
||||
final LivingEntity entity = (LivingEntity) (Object) this;
|
||||
@@ -128,31 +116,4 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$conditionalWaterBreathing(
|
||||
int currentAir,
|
||||
CallbackInfoReturnable<Integer> cir
|
||||
) {
|
||||
var entity = (LivingEntity) (Object) this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player.getVehicle() instanceof PokemonEntity vehicle)) return;
|
||||
|
||||
var ridingController = vehicle.getRidingController();
|
||||
if (ridingController == null) return;
|
||||
|
||||
var activeContext = ridingController.getContext();
|
||||
if (activeContext == null) return;
|
||||
|
||||
// If the rider is currently on a submarine and the ride still has stamina.
|
||||
var stamina = activeContext.getState().getStamina().get();
|
||||
if (
|
||||
activeContext.getStyle() == RidingStyle.LIQUID &&
|
||||
activeContext.getBehaviour().equals(SubmarineBehaviour.Companion.getKEY()) &&
|
||||
stamina > 0.0f
|
||||
) {
|
||||
cir.setReturnValue(currentAir);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
@@ -48,7 +47,6 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -65,7 +63,7 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck {
|
||||
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@@ -93,12 +91,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
@Shadow protected int jumpTriggerTime;
|
||||
@Unique private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
@Unique private float cobblemon$rideXRot = 0.0f;
|
||||
|
||||
@Unique private float cobblemon$rideYRot = 0.0f;
|
||||
|
||||
@Unique private Vec3 cobblemon$rideEyePos = Vec3.ZERO;
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
super(p_20966_, p_20967_);
|
||||
}
|
||||
@@ -125,6 +117,11 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
|
||||
this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
@@ -310,34 +307,4 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
return cobblemon$lastSentDriverInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideXRot() {
|
||||
return this.cobblemon$rideXRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideXRot(float rideXRot) {
|
||||
this.cobblemon$rideXRot = rideXRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideYRot() {
|
||||
return this.cobblemon$rideYRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideYRot(float rideYRot) {
|
||||
this.cobblemon$rideYRot = rideYRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 cobblemon$getRideEyePos() {
|
||||
return this.cobblemon$rideEyePos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideEyePos(Vec3 rideEyePos) {
|
||||
this.cobblemon$rideEyePos = rideEyePos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -26,17 +25,16 @@ public abstract class ServerPlayerMixin {
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation(vehicle);
|
||||
controllableVehicle.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((ServerPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(Entity entity) {
|
||||
if (entity == null) return false;
|
||||
if (!(entity instanceof PokemonEntity pokemonEntity)) return false;
|
||||
private boolean cobblemon$shouldUseCustomOrientation(ServerPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
@@ -44,9 +42,8 @@ public abstract class ServerPlayerMixin {
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
//TODO: Switch to sending out on load instead of preventing saving
|
||||
|
||||
@@ -1,21 +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.mixin.accessor;
|
||||
|
||||
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.level.block.entity.BeehiveBlockEntity$BeeData")
|
||||
public interface BeeDataAccessor {
|
||||
@Invoker("toOccupant")
|
||||
BeehiveBlockEntity.Occupant invokeToOccupant();
|
||||
}
|
||||
|
||||
-40
@@ -1,40 +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.mixin.accessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public interface BeehiveBlockEntityAccessor {
|
||||
@Accessor("stored")
|
||||
List<Object> getStored();
|
||||
@Accessor("savedFlowerPos")
|
||||
BlockPos savedFlowerPos();
|
||||
|
||||
|
||||
/**
|
||||
* Access the private static method:
|
||||
* private static void releaseOccupant(Level level, BlockPos pos, BeeData beeData, ...)
|
||||
*/
|
||||
@Invoker("releaseOccupant")
|
||||
static boolean releaseOccupant(Level level, BlockPos pos, BlockState state, BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> storedInHives, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos storedFlowerPos) {
|
||||
throw new AssertionError(); // Mixin will overwrite
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +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.mixin.accessor;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(BlockEntity.class)
|
||||
public interface BlockEntityAccessor {
|
||||
@Accessor("level") Level getLevel();
|
||||
@Accessor("worldPosition") BlockPos getWorldPosition();
|
||||
}
|
||||
+1
-2
@@ -34,8 +34,7 @@ public class AbstractClientPlayerMixin {
|
||||
} else {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
// Only modify fov for the driver and not the passengers
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
// Return custom fov mult for riding
|
||||
|
||||
@@ -14,15 +14,12 @@ import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix3f;
|
||||
@@ -36,9 +33,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static net.minecraft.util.Mth.abs;
|
||||
import static net.minecraft.util.Mth.atan2;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public abstract class CameraMixin {
|
||||
@Shadow private Entity entity;
|
||||
@@ -54,43 +48,45 @@ public abstract class CameraMixin {
|
||||
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Shadow private float partialTickTime;
|
||||
|
||||
// Used to help in camera rotation rendering when transitioning
|
||||
// from rolled to unrolled.
|
||||
@Unique private float cobblemon$returnTimer = 0;
|
||||
@Unique private float cobblemon$rollAngleStart = 0;
|
||||
|
||||
@Unique private double cobblemon$lastHandledRotationTime = Double.MIN_VALUE;
|
||||
@Unique private double cobblemon$frameTime = 0.0;
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
// Calculate the current frametime
|
||||
double d = Blaze3D.getTime();
|
||||
this.cobblemon$frameTime = (this.cobblemon$lastHandledRotationTime != Double.MIN_VALUE) ? d - this.cobblemon$lastHandledRotationTime : 0.0;
|
||||
this.cobblemon$lastHandledRotationTime = d;
|
||||
|
||||
var vehicle = this.entity.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var instance = (Camera)(Object)this;
|
||||
|
||||
// If the current vehicle has no orientation then return and perform
|
||||
// vanilla camera rotations
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
if (vehicleController.getOrientation() == null) return;
|
||||
|
||||
// If the controller has been deactivated but the orientation isn't null yet
|
||||
// then perform transition from rolled ride/camera to vanilla
|
||||
if (!vehicleController.isActive() && vehicleController.getOrientation() != null) {
|
||||
cobblemon$applyTransitionRotation(vehicleController, ci);
|
||||
} else { // Otherwise perform cobblemon specific camera rotation and set transition helper variables
|
||||
cobblemon$applyRotation();
|
||||
this.cobblemon$returnTimer = 0;
|
||||
this.cobblemon$rollAngleStart = instance.rotation().getEulerAnglesYXZ(new Vector3f()).z();
|
||||
ci.cancel();
|
||||
if (!(this.entity instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
if(this.returnTimer < 1) {
|
||||
//Rotation is taken from entity since we no longer handle mouse ourselves
|
||||
//Stops a period of time when you can't input anything.
|
||||
controller.getOrientation().set(
|
||||
new Matrix3f()
|
||||
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
|
||||
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
|
||||
);
|
||||
if(rollAngleStart == 0){
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
return;
|
||||
}
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
cobblemon$applyRotation();
|
||||
this.returnTimer += .05F;
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (controller.getOrientation() == null) return;
|
||||
cobblemon$applyRotation();
|
||||
|
||||
this.returnTimer = 0;
|
||||
this.rollAngleStart = controller.getRoll();
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
|
||||
@@ -123,128 +119,20 @@ public abstract class CameraMixin {
|
||||
|
||||
@Unique
|
||||
private void cobblemon$applyRotation(){
|
||||
var driver = this.entity;
|
||||
if (!(driver.getVehicle() instanceof OrientationControllable controllableVehicle) ||
|
||||
controllableVehicle.getOrientationController().getOrientation() == null ||
|
||||
!controllableVehicle.getOrientationController().getActive()
|
||||
) return;
|
||||
|
||||
// Grab the driver and vehicle orientation controllers.
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
|
||||
var isDriving = driver.getControlledVehicle() != null;
|
||||
|
||||
// Grab the ride orientation
|
||||
var newRotation = new Quaternionf();
|
||||
|
||||
// If the player is driving then use the current orientation since the driver sets it.
|
||||
// If not then use the smoothed render orientation for passengers otherwise the vehicle rotation will be jerky
|
||||
if (isDriving) {
|
||||
newRotation = vehicleController.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
} else {
|
||||
newRotation = vehicleController.getRenderOrientation(this.partialTickTime);
|
||||
}
|
||||
|
||||
// Unroll the current rotation if no roll is requested
|
||||
if (Cobblemon.config.getDisableRoll()) {
|
||||
var eulerAngs = newRotation.getEulerAnglesYXZ(new Vector3f());
|
||||
var currAngs = this.rotation.getEulerAnglesYXZ(new Vector3f());
|
||||
var vehicle = (PokemonEntity)driver.getVehicle();
|
||||
var vel = vehicle.getRidingAnimationData().getVelocitySpring().getInterpolated(this.partialTickTime, 0);
|
||||
|
||||
// lerp the new rotation towards this y rot at a rate proportional to the horizontal movement speed?
|
||||
var yaw = Mth.wrapDegrees(Math.toDegrees(Mth.atan2(vel.x(), vel.z())) + 180.0f);
|
||||
|
||||
var degDiff = Mth.degreesDifference((float)Math.toDegrees(currAngs.y()), (float)yaw);
|
||||
var pitchDeadzoneDeg = 15.0; // x degrees of deadzone about +-90 degrees of pitch.
|
||||
var pitchDeg = vehicleController.getPitch();
|
||||
// ConsiderPitch to be already 90 if within the deadzone around it.
|
||||
var cutoffPitch = Math.min(1.0,(Mth.abs(pitchDeg) / (90.0f - pitchDeadzoneDeg))) * 90.0f * Math.signum(pitchDeg);
|
||||
var lerpRateMod = Mth.cos((float)Math.toRadians(cutoffPitch));
|
||||
|
||||
// Apply smoothing from the cameras current yaw to the yaw of the velocity vector of the ride.
|
||||
var k = 2.0f; // Some smoothing constant k
|
||||
var smoothingFactor = lerpRateMod * cobblemon$frameTime * k;
|
||||
var newYaw = currAngs.y() + (Math.toRadians(degDiff) * smoothingFactor);
|
||||
|
||||
newRotation.set(new Quaternionf().rotateYXZ((float)newYaw, eulerAngs.x(), 0.0f));
|
||||
}
|
||||
|
||||
var k = 0;
|
||||
if (Minecraft.getInstance().options.getCameraType().isMirrored()) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
var newRotation = controller.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
if (this.minecraft.options.getCameraType().isMirrored()) {
|
||||
newRotation.rotateY((float)Math.toRadians(180));
|
||||
k = 180;
|
||||
}
|
||||
|
||||
// Get the drivers local look angle in relation to the ride and apply it.
|
||||
if (vehicleController.getActive()) {
|
||||
var vehicleMatrix = new Matrix3f().set(newRotation);
|
||||
var driverMatrix = new Matrix3f();// Base the driver
|
||||
var playerRotater = (RidePassenger)driver;
|
||||
newRotation = vehicleMatrix.mul(
|
||||
driverMatrix.rotateYXZ(
|
||||
-Mth.DEG_TO_RAD * (playerRotater.cobblemon$getRideYRot()),
|
||||
-Mth.DEG_TO_RAD * playerRotater.cobblemon$getRideXRot(),
|
||||
0.0f)
|
||||
).normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
}
|
||||
this.rotation.set(newRotation);
|
||||
var eulerAngs = newRotation.getEulerAnglesXYZ(new Vector3f());
|
||||
this.xRot = eulerAngs.x() * Mth.RAD_TO_DEG;
|
||||
this.yRot = eulerAngs.y() * Mth.RAD_TO_DEG;
|
||||
// Set the drivers rotations to match
|
||||
var driverEulerAngs = new Quaternionf(this.rotation).getEulerAnglesYXZ(new Vector3f());
|
||||
driver.setXRot(-driverEulerAngs.x() * Mth.RAD_TO_DEG + k);
|
||||
driver.setYRot(180.0f - (driverEulerAngs.y() * Mth.RAD_TO_DEG));
|
||||
|
||||
this.xRot = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$applyTransitionRotation(
|
||||
OrientationController vehicleController,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
// If the transition has just started then
|
||||
if (this.cobblemon$returnTimer == 0.0) {
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
}
|
||||
|
||||
if(this.cobblemon$returnTimer < 1) {
|
||||
//Rotation is taken from entity since we no longer handle mouse ourselves
|
||||
//Stops a period of time when you can't input anything.
|
||||
float interpolatedRoll = Mth.lerp(this.cobblemon$returnTimer, this.cobblemon$rollAngleStart, 0.0f);
|
||||
float pitch = (float) Math.toRadians(-this.entity.getXRot());
|
||||
float yaw = (float) Math.toRadians(180 - this.entity.getYRot());
|
||||
|
||||
Quaternionf interRot = new Quaternionf();
|
||||
interRot.rotationYXZ(yaw, pitch, interpolatedRoll);
|
||||
|
||||
this.rotation.set(interRot);
|
||||
var eulerAngs = interRot.getEulerAnglesXYZ(new Vector3f());
|
||||
this.xRot = eulerAngs.x() * Mth.RAD_TO_DEG;
|
||||
this.yRot = eulerAngs.y() * Mth.RAD_TO_DEG;
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
|
||||
if(cobblemon$rollAngleStart == 0){
|
||||
this.cobblemon$returnTimer = 1;
|
||||
vehicleController.reset();
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
return;
|
||||
}
|
||||
this.cobblemon$returnTimer += (partialTickTime * (1.0f/20.0f));
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.cobblemon$returnTimer = 1;
|
||||
vehicleController.reset();
|
||||
MountedCameraRenderer.INSTANCE.resetDriverRotations((Camera)(Object)this, this.entity);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
public void stopMoveIfRolling(Camera instance, float zoom, float dy, float dx, Operation<Void> original) {
|
||||
Entity entity = instance.getEntity();
|
||||
|
||||
@@ -19,11 +19,9 @@ import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -31,10 +29,12 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.Input;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -83,33 +83,19 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void cobblemon$updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
if (!vehicleController.isActive() || vehicleController.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = vehicleController.getOrientation() != null ? new Matrix3f(vehicleController.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(this.getVehicle().getId(), vehicleController.getOrientation()));
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
var driver = (LocalPlayer)(Object)this;
|
||||
var vehicle = driver.getVehicle();
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
|
||||
// If the player has just switched to riding a custom orientation ride then set their
|
||||
// x and y rots local to the vehicle rots(if the controller wasn't active and will now be active)
|
||||
// This ensures that on transition your camera stays in the same spot
|
||||
if (!vehicleController.isActive() && shouldUseCustomOrientation) {
|
||||
// Set local to the vehicle x and yrot so
|
||||
var playerRotater = (RidePassenger)driver;
|
||||
playerRotater.cobblemon$setRideXRot(Mth.wrapDegrees(driver.getXRot() - vehicle.getXRot()));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.wrapDegrees(driver.getYRot() - vehicle.getYRot()));
|
||||
}
|
||||
|
||||
vehicleController.setActive(shouldUseCustomOrientation);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
@@ -129,27 +115,6 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(driverInput));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRiderRotationsRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
|
||||
// Only send rotation updates if the player is riding a vehicle that is currently rollable
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
if (!controllableVehicle.getOrientationController().getActive()) return;
|
||||
|
||||
var passenger = (LocalPlayer)(Object)this;
|
||||
var playerRotater = (RidePassenger)passenger;
|
||||
|
||||
// Gather Rider Rotation info
|
||||
var rideXRot = playerRotater.cobblemon$getRideXRot();
|
||||
var rideYRot = playerRotater.cobblemon$getRideYRot();
|
||||
var rideEyePos = playerRotater.cobblemon$getRideEyePos();
|
||||
|
||||
// Send new info to server. Currently not checking to see if this has change substantially
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos));
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
@@ -164,8 +129,8 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
public void stopRiding() {
|
||||
super.stopRiding();
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
|
||||
@@ -10,16 +10,13 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import kotlin.Pair;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
@@ -35,9 +32,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static com.google.common.primitives.Floats.min;
|
||||
import static net.minecraft.util.Mth.lerp;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public abstract class MouseHandlerMixin {
|
||||
@Shadow private double accumulatedScrollY;
|
||||
@@ -132,22 +126,20 @@ public abstract class MouseHandlerMixin {
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6 + 0.2;
|
||||
var spyglassSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
var lookSensitivity = spyglassSensitivity * 8.0;
|
||||
var sensitivity = lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
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));
|
||||
returnValue = false;
|
||||
}
|
||||
|
||||
var vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof PokemonEntity)) return true;
|
||||
|
||||
// Clamp player rotation if riding and the vehicle demands it
|
||||
if (player.isPassenger() && vehicle instanceof PokemonEntity pokeVehicle) {
|
||||
pokeVehicle.clampPassengerRotation(player);
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity vehicle) {
|
||||
vehicle.clampPassengerRotation(player);
|
||||
}
|
||||
|
||||
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
|
||||
if (!(player instanceof OrientationControllable controllable)) return true;
|
||||
|
||||
if (!controllable.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
@@ -156,55 +148,12 @@ public abstract class MouseHandlerMixin {
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
var lookaroundButtonPressed = Minecraft.getInstance().mouseHandler.isMiddlePressed();
|
||||
Pair<Boolean, Boolean> mouseShouldModifyDriver = ((PokemonEntity) vehicle).ifRidingAvailableSupply(new Pair(false, false), (behaviour, settings, state) -> {
|
||||
return behaviour.mouseModifiesDriverRotation(
|
||||
settings,
|
||||
state,
|
||||
(PokemonEntity) vehicle
|
||||
);
|
||||
});
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// If looking around then modify the players orientation instead and zero the mouse deltas so the mouse doesn't
|
||||
// affect the vehicle orientation when looking around.
|
||||
// If the client is a passenger it will modify these rotations and return
|
||||
//-------------------------------------------------------------------------
|
||||
if (lookaroundButtonPressed || player.getControlledVehicle() == null) {
|
||||
// Modify driver rotations
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, cursorDeltaY);
|
||||
|
||||
// If the player/passenger is not the driver then return and ignore all vehicle rotation logic
|
||||
if (player.getControlledVehicle() == null) return false;
|
||||
|
||||
// Set to zero so that vehicle rotations don't also get affected by movement.
|
||||
cursorDeltaX = 0.0;
|
||||
cursorDeltaY = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getFirst()) { // If not freelooking then check modification per mouse input dimension
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, 0.0);
|
||||
cursorDeltaX = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getSecond()) {
|
||||
cobblemon$setDriverRotations(player, 0.0, cursorDeltaY);
|
||||
cursorDeltaY = 0.0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Smoothly return driver rotations to zero when needed
|
||||
//-------------------------------------------------------------------------
|
||||
var playerRotater = (RidePassenger)player;
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getFirst()){
|
||||
playerRotater.cobblemon$setRideYRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideYRot()), 0.0f));
|
||||
}
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getSecond()) {
|
||||
playerRotater.cobblemon$setRideXRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideXRot()), 0.0f));
|
||||
}
|
||||
|
||||
// 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.
|
||||
vehicleController.rotate(
|
||||
controllable.getOrientationController().rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
@@ -214,16 +163,17 @@ public abstract class MouseHandlerMixin {
|
||||
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()) {
|
||||
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);
|
||||
vehicleController.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
controllable.getOrientationController().rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
// Otherwise simply apply the smoothing
|
||||
else {
|
||||
vehicleController.rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -236,11 +186,10 @@ public abstract class MouseHandlerMixin {
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("TAIL"))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player.getVehicle() instanceof OrientationControllable vehicleControllable)) return;
|
||||
if (!(vehicleControllable.getOrientationController() instanceof OrientationController vehicleController)) return;
|
||||
if (vehicleController.getOrientation() == null) return;
|
||||
if (!(minecraft.player instanceof OrientationControllable controllable)) return;
|
||||
if (!controllable.getOrientationController().isActive()) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
if (this.isMouseGrabbed()) return; // return if turnPlayer() has already run this pass
|
||||
if (isMouseGrabbed()) return;
|
||||
|
||||
this.turnPlayer(cobblemon$timeDelta);
|
||||
}
|
||||
@@ -302,20 +251,6 @@ public abstract class MouseHandlerMixin {
|
||||
return Math.pow(sensitivity, 3);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$setDriverRotations(LocalPlayer player, double cursorDeltaX, double cursorDeltaY) {
|
||||
// the vanilla turn() method redone so that it uses rideRotations.
|
||||
float f = (float)cursorDeltaY * 0.15F; // Note: turn() uses xRot for pitch (up/down)
|
||||
float g = (float)cursorDeltaX * 0.15F; // Note: turn() uses yRot for yaw (left/right)
|
||||
var playerRotater = (RidePassenger)player;
|
||||
playerRotater.cobblemon$setRideXRot(playerRotater.cobblemon$getRideXRot() + f);
|
||||
playerRotater.cobblemon$setRideYRot(playerRotater.cobblemon$getRideYRot() + g);
|
||||
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -90.0F, 90.0F));
|
||||
if (player.getVehicle() != null) {
|
||||
player.getVehicle().onPassengerTurned(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseAngVelSmoothing() {
|
||||
var player = minecraft.player;
|
||||
|
||||
@@ -8,24 +8,20 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.entity;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
public abstract class EntityMixin {
|
||||
@@ -61,46 +57,5 @@ public abstract class EntityMixin {
|
||||
return original.call(entity);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getEyePosition(F)Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$modifyEyePosition_partial(float partialTicks, CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
if (vehicleController == null) return;
|
||||
|
||||
// If Orientation is currently being controlled then use the stored eye position from camera positioning.
|
||||
if (vehicleController.getActive() && vehicleController.getOrientation() != null) {
|
||||
// TODO: Determine if it needs partialtick involved.
|
||||
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getEyePosition()Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$modifyEyePosition_noPartial(CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
if (vehicleController == null) return;
|
||||
|
||||
// If Orientation is currently being controlled then use the stored eye position from camera positioning.
|
||||
if (vehicleController.getActive() && vehicleController.getOrientation() != null) {
|
||||
// TODO: Determine if it needs partialtick involved.
|
||||
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.GlobalPos
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.*
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
@@ -48,13 +48,10 @@ object CobblemonMemories {
|
||||
val TIME_TRYING_TO_REACH_BERRY_BUSH = register<Int>("time_trying_to_reach_berry_bush")
|
||||
val IS_CONSUMING_ITEM = register<Boolean>("is_consuming_item")
|
||||
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location", BlockPos.CODEC)
|
||||
val HIVE_BLACKLIST = register<List<BlockPos>>("hive_blacklist")
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location")
|
||||
val HIVE_COOLDOWN = register<Boolean>("hive_cooldown")
|
||||
val NEARBY_FLOWER = register<BlockPos>("nearby_flower", BlockPos.CODEC)
|
||||
val PATH_TO_NEARBY_FLOWER_COOLDOWN = register<Boolean>("path_to_nearby_flower_cooldown")
|
||||
val HAS_NECTAR = register<Boolean>("has_nectar", PrimitiveCodec.BOOL)
|
||||
val NEARBY_SACC_LEAVES = register<BlockPos>("nearby_sacc_leaves", BlockPos.CODEC)
|
||||
val NEARBY_FLOWERS = register<List<BlockPos>>("nearby_flower")
|
||||
val POLLINATED = register<Boolean>("pollinated", PrimitiveCodec.BOOL)
|
||||
/** who am i following rn? */
|
||||
val HERD_LEADER = register<String>("herd_leader", PrimitiveCodec.STRING)
|
||||
/** how many are following me rn? */
|
||||
|
||||
@@ -179,7 +179,6 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePa
|
||||
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
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
@@ -232,7 +231,6 @@ import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHan
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdateRiderRotationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
|
||||
@@ -586,7 +584,6 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingSettingsPacket.ID, ServerboundUpdateRidingSettingsPacket::decode, ServerboundUpdateRidingSettingsHandler))
|
||||
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateDriverInputPacket.ID, ServerboundUpdateDriverInputPacket::decode, DriverInputPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRiderRotationPacket.ID, ServerboundUpdateRiderRotationPacket::decode, ServerboundUpdateRiderRotationHandler))
|
||||
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineSettings
|
||||
import com.cobblemon.mod.common.net.messages.client.data.RideSettingsSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
@@ -64,7 +63,6 @@ object CobblemonRideSettings : DataRegistry {
|
||||
var boat = BoatSettings()
|
||||
var burst = BurstSettings()
|
||||
var dolphin = DolphinSettings()
|
||||
var submarine = SubmarineSettings()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(
|
||||
@@ -80,8 +78,7 @@ object CobblemonRideSettings : DataRegistry {
|
||||
vehicle = vehicle,
|
||||
boat = boat,
|
||||
burst = burst,
|
||||
dolphin = dolphin,
|
||||
submarine = submarine
|
||||
dolphin = dolphin
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -99,7 +96,6 @@ object CobblemonRideSettings : DataRegistry {
|
||||
boat = loadStyle(manager, "boat", BoatSettings::class.java)
|
||||
burst = loadStyle(manager, "burst", BurstSettings::class.java)
|
||||
dolphin = loadStyle(manager, "dolphin", DolphinSettings::class.java)
|
||||
submarine = loadStyle(manager, "submarine", SubmarineSettings::class.java)
|
||||
}
|
||||
|
||||
private fun <T : RidingBehaviourSettings> loadStyle(manager: ResourceManager, name: String, clazz: Class<T>): T {
|
||||
|
||||
@@ -41,8 +41,6 @@ object CobblemonSensors {
|
||||
|
||||
val POKEMON_NEARBY_WANTED_ITEM = register("pokemon_nearby_wanted_item", ::PokemonItemSensor)
|
||||
|
||||
val NEARBY_SACC_LEAVES = register("nearby_sacc_leaves", ::SacLeavesSensor)
|
||||
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
|
||||
+1
-2
@@ -17,7 +17,6 @@ import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -63,7 +62,7 @@ class MemoryAspectTaskConfig : SingleTaskConfig {
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long) = true
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
val hasMemory = owner.brain.hasMemoryValue(memory)
|
||||
val hasMemory = !owner.brain.hasMemoryValue(memory)
|
||||
if (owner is PokemonEntity) {
|
||||
if (!hasMemory && aspect in owner.pokemon.forcedAspects) {
|
||||
owner.pokemon.forcedAspects -= aspect
|
||||
|
||||
+2
-118
@@ -8,31 +8,16 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
|
||||
import com.cobblemon.mod.common.util.distanceTo
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToBeeHiveTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
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 PathToBeeHiveTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val HONEY = "honey"
|
||||
const val STAY_OUT_OF_HIVE_COOLDOWN = 400
|
||||
|
||||
}
|
||||
|
||||
val condition = booleanVariable(HONEY, "can_add_honey", true).asExpressible()
|
||||
@@ -51,107 +36,6 @@ class PathToBeeHiveTaskConfig : SingleTaskConfig {
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE)
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
MemoryModuleType.LOOK_TARGET to MemoryStatus.REGISTERED,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
|
||||
CobblemonMemories.HIVE_LOCATION to MemoryStatus.VALUE_PRESENT,
|
||||
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HIVE_BLACKLIST to MemoryStatus.REGISTERED,
|
||||
),
|
||||
400,
|
||||
400
|
||||
) {
|
||||
|
||||
val maxTicks = 400
|
||||
var traveledTicks = 0
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
return (owner is PathfinderMob && owner.isAlive && (owner is PokemonEntity && PlaceHoneyInHiveTask.wantsToEnterHive(owner))) && owner.brain.checkMemory(
|
||||
MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
if (maxTicks >= traveledTicks) return false
|
||||
val pos = entity.brain.getMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
return !pos.isEmpty && entity.distanceTo(pos.get()) > 1.0
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
super.start(level, entity, gameTime)
|
||||
val hiveLocation = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
val world = entity.level()
|
||||
val sidesByClosest = listOf(
|
||||
hiveLocation.north(),
|
||||
hiveLocation.south(),
|
||||
hiveLocation.east(),
|
||||
hiveLocation.west()
|
||||
).sortedBy { it.distSqr(entity.blockPosition()) }
|
||||
|
||||
var openSide = BlockPos.ZERO
|
||||
for (side in sidesByClosest) {
|
||||
if (world.getBlockState(side).isAir) {
|
||||
openSide = side
|
||||
break
|
||||
}
|
||||
}
|
||||
if (openSide == BlockPos.ZERO) {
|
||||
if (world.getBlockState(hiveLocation.above()).isAir) {
|
||||
// If the above position is also air, we can use it
|
||||
openSide = hiveLocation.above() // Fallback to above if no open sides found
|
||||
} else if (world.getBlockState(hiveLocation.below()).isAir) {
|
||||
// If the below position is also air, we can use it
|
||||
openSide = hiveLocation.below() // Fallback to below if no open sides found
|
||||
} else {
|
||||
// If no open sides or above/below positions are found, we cannot proceed
|
||||
return
|
||||
}
|
||||
}
|
||||
val targetVec = Vec3.atCenterOf(openSide)
|
||||
|
||||
// Set path target toward hive
|
||||
if (pathfindDirectlyTowards(openSide, entity)) {
|
||||
entity.brain.setMemory(MemoryModuleType.WALK_TARGET,WalkTarget(targetVec, 0.35F, 0))
|
||||
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET,BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
traveledTicks = 0
|
||||
} else {
|
||||
dropAndBlackListHive(entity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
traveledTicks++
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (maxTicks < traveledTicks) {
|
||||
dropAndBlackListHive(entity)
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, 100)
|
||||
}
|
||||
}
|
||||
|
||||
fun dropAndBlackListHive(entity: LivingEntity) {
|
||||
val hivePos = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
if (hivePos == null) return
|
||||
val blackList = entity.brain.getMemorySafely(CobblemonMemories.HIVE_BLACKLIST).orElse(emptyList()).toMutableList()
|
||||
|
||||
blackList.add(hivePos)
|
||||
if (blackList.count() > 3) {
|
||||
blackList.removeFirst()
|
||||
}
|
||||
entity.brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
entity.brain.setMemory(CobblemonMemories.HIVE_BLACKLIST, blackList)
|
||||
|
||||
}
|
||||
|
||||
private fun pathfindDirectlyTowards(pos: BlockPos, entity: LivingEntity): Boolean {
|
||||
if (entity !is PathfinderMob) return false
|
||||
val nav = entity.navigation
|
||||
val path = nav. createPath(pos, 0)
|
||||
return path != null && path.canReach()
|
||||
}
|
||||
}
|
||||
return PathToBeeHiveTask.create()
|
||||
}
|
||||
}
|
||||
+4
-5
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
@@ -40,14 +41,12 @@ class PathToFlowerTaskConfig : SingleTaskConfig {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.NEARBY_FLOWER,
|
||||
CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN,
|
||||
CobblemonMemories.NEARBY_FLOWERS,
|
||||
CobblemonMemories.HIVE_COOLDOWN,
|
||||
CobblemonMemories.HIVE_LOCATION,
|
||||
CobblemonMemories.HIVE_BLACKLIST,
|
||||
CobblemonMemories.HAS_NECTAR,
|
||||
CobblemonMemories.POLLINATED
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_FLOWER)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE, CobblemonSensors.NEARBY_FLOWER)
|
||||
return PathToFlowerTask.create()
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +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.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToSacLeafTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class PathToSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.NEARBY_SACC_LEAVES,
|
||||
CobblemonMemories.HAS_NECTAR
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_SACC_LEAVES, CobblemonSensors.NEARBY_FLOWER)
|
||||
return PathToSacLeafTask.create()
|
||||
}
|
||||
}
|
||||
+2
-5
@@ -8,8 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
|
||||
@@ -37,9 +37,6 @@ class PlaceHoneyInHiveTaskConfig : SingleTaskConfig {
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
return WrapperLivingEntityTask(
|
||||
PlaceHoneyInHiveTask.create(),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
return PlaceHoneyInHiveTask.create()
|
||||
}
|
||||
}
|
||||
-130
@@ -1,130 +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.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
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.phys.Vec3
|
||||
|
||||
class PlaceHoneyInSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
const val MIN_DURATION : Int = 300
|
||||
const val MAX_DURATION : Int = 400
|
||||
const val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 250
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
CobblemonMemories.NEARBY_SACC_LEAVES to MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.VALUE_PRESENT,
|
||||
),
|
||||
MIN_DURATION,
|
||||
MAX_DURATION
|
||||
) {
|
||||
var successfulPollinationTicks = 0
|
||||
var lastSoundPlayedTick = 0
|
||||
var hoverPos: Vec3? = null
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
if (level.isNight || level.isRaining || !(entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false))) return false
|
||||
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES)
|
||||
if (!optionalBlockPos.isPresent || level.getBlockState(optionalBlockPos.get()).block != CobblemonBlocks.SACCHARINE_LEAVES) return false
|
||||
return Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 0.6
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
|
||||
CobblemonActivities.POKEMON_POLLINATION) != -1
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
super.start(level, entity, gameTime)
|
||||
hoverPos = null
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
++successfulPollinationTicks
|
||||
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
|
||||
this.lastSoundPlayedTick = successfulPollinationTicks
|
||||
entity.playSound(SoundEvents.BEEHIVE_DRIP, 1.0f, 1.0f)
|
||||
}
|
||||
val leavesPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
|
||||
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
|
||||
val bl3 = entity.random.nextInt(40) == 0
|
||||
if (bl && bl3) {
|
||||
// mimics the wriggling over a flower the vanilla bees do
|
||||
if (hoverPos == null) {
|
||||
hoverPos = leavesPos.bottomCenter.add(0.0, 0.4, 0.0)
|
||||
}
|
||||
if (leavesPos != null) {
|
||||
hoverPos = leavesPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
entity.lookControl.setLookAt(leavesPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
}
|
||||
} else if (!bl) {
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
val blockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
blockPos.let {
|
||||
val blockState = level.getBlockState(blockPos)
|
||||
if (blockState.block == CobblemonBlocks.SACCHARINE_LEAVES) {
|
||||
val saccAge = blockState.getValue( SaccharineLeafBlock.AGE)
|
||||
if (saccAge < SaccharineLeafBlock.MAX_AGE) {
|
||||
entity.brain.eraseMemory(CobblemonMemories.HAS_NECTAR)
|
||||
val newBlockState = blockState.setValue(SaccharineLeafBlock.AGE, saccAge + 1)
|
||||
level.setBlock(blockPos, newBlockState, 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
successfulPollinationTicks = 0
|
||||
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
-52
@@ -8,14 +8,17 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
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.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.sendParticlesServer
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -26,11 +29,10 @@ import net.minecraft.world.phys.Vec3
|
||||
class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
const val PATH_TO_FLOWER_COOLDOWN_TICKS : Long = 200
|
||||
const val HAS_NECTAR_ASPECT = "has_nectar"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
val durationTicks: ExpressionOrEntityVariable = Either.left("30".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
@@ -49,28 +51,22 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
CobblemonMemories.NEARBY_FLOWER to MemoryStatus.VALUE_PRESENT,
|
||||
CobblemonMemories.NEARBY_FLOWERS to MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
|
||||
CobblemonMemories.POLLINATED to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
|
||||
),
|
||||
600,
|
||||
625
|
||||
15,
|
||||
45
|
||||
) {
|
||||
val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 400
|
||||
var successfulPollinationTicks = 0
|
||||
var lastSoundPlayedTick = 0
|
||||
var hoverPos: Vec3? = null
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
if (level.isNight || level.isRaining || entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false)) return false
|
||||
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER)
|
||||
return optionalBlockPos.isPresent && Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 1.0
|
||||
return entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWERS).orElse(emptyList()).any {
|
||||
Vec3.atCenterOf(it).distanceTo(entity.position()) <= 1.0
|
||||
}
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
|
||||
CobblemonActivities.POKEMON_POLLINATION) != -1
|
||||
return checkExtraStartConditions(level, entity)
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
@@ -78,44 +74,20 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
++successfulPollinationTicks
|
||||
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
|
||||
this.lastSoundPlayedTick = successfulPollinationTicks
|
||||
entity.playSound(SoundEvents.BEE_POLLINATE, 1.0f, 1.0f)
|
||||
}
|
||||
val flowerPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER).orElse(null)
|
||||
|
||||
|
||||
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
|
||||
val bl3 = entity.random.nextInt(40) == 0
|
||||
if (bl && bl3) {
|
||||
// mimics the wriggling over a flower the vanilla bees do
|
||||
if (hoverPos == null) {
|
||||
hoverPos = flowerPos.bottomCenter.add(0.0, 0.4, 0.0)
|
||||
}
|
||||
|
||||
if (flowerPos != null) {
|
||||
hoverPos = flowerPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
}
|
||||
} else if (!bl) {
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
}
|
||||
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
|
||||
level.sendParticlesServer(
|
||||
particleType = ParticleTypes.DRIPPING_HONEY,
|
||||
position = owner.eyePosition,
|
||||
particles = 3,
|
||||
offset = Vec3.ZERO,
|
||||
speed = 0.0
|
||||
)
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
entity.brain.setMemory(CobblemonMemories.HAS_NECTAR, true)
|
||||
val flowerStillThere = canStillUse(level, entity, gameTime)
|
||||
if (flowerStillThere) {
|
||||
entity.brain.setMemory(CobblemonMemories.POLLINATED, true)
|
||||
}
|
||||
successfulPollinationTicks = 0
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN, true, PATH_TO_FLOWER_COOLDOWN_TICKS)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,9 +97,7 @@ interface TaskConfig {
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("path_to_hive") to PathToBeeHiveTaskConfig::class.java,
|
||||
cobblemonResource("place_honey_in_hive") to PlaceHoneyInHiveTaskConfig::class.java,
|
||||
cobblemonResource("place_honey_in_sacc_leaves") to PlaceHoneyInSaccLeavesTaskConfig::class.java,
|
||||
cobblemonResource("path_to_flower") to PathToFlowerTaskConfig::class.java,
|
||||
cobblemonResource("path_to_sacc_leaves") to PathToSaccLeavesTaskConfig::class.java,
|
||||
cobblemonResource("pollinate_flower") to PollinateFlowerTaskConfig::class.java,
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("manage_flight_in_battle") to ManageFlightInBattleTaskConfig::class.java,
|
||||
|
||||
-2
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.aspect
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PollinateFlowerTaskConfig
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SaccharineLogSlatheredInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.LurePokeSnackDetector
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
@@ -28,7 +27,6 @@ val aspectParticleMap: Map<String, ParticleData> = mapOf(
|
||||
ParticleTypes.BLOCK,
|
||||
CobblemonBlocks.POKE_SNACK.defaultBlockState()
|
||||
), 0.05, 3),
|
||||
PollinateFlowerTaskConfig.HAS_NECTAR_ASPECT to ParticleData.MinecraftParticle(ParticleTypes.FALLING_NECTAR, 0.075, 1)
|
||||
)
|
||||
|
||||
sealed class ParticleData {
|
||||
|
||||
-12
@@ -103,18 +103,6 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
|
||||
*/
|
||||
fun damageOnCollision(settings: Settings, state: State, vehicle: PokemonEntity, impactVec: Vec3): Boolean = false
|
||||
|
||||
/**
|
||||
* Called in [com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer] to allow the controller to set rotations
|
||||
* through code using partialTicks and right before rendering.
|
||||
* //TODO: This needs to be further refined. Maybe only the orientationController needs affected? Maybe the rotations set here don't need to be applied to the controller/camera
|
||||
*/
|
||||
fun applyRenderRotation(settings: Settings, state: State, vehicle: PokemonEntity, partialTicks: Float) {}
|
||||
|
||||
/**
|
||||
* Determines if the pair of mouse inputs Pair(mouseX, mouseY) get used to modify the driverRotations or the vehicle rotations themselves.
|
||||
* Driver rotations are the rotations used by passengers or a driver that is freelooking. This does not override the freelook button.
|
||||
*/
|
||||
fun mouseModifiesDriverRotation(settings: Settings, state: State, vehicle: PokemonEntity): Pair<Boolean, Boolean> = Pair(false, false)
|
||||
|
||||
/**
|
||||
* Internal helpers to help behaviour specific calculations
|
||||
|
||||
+1
-1
@@ -30,6 +30,6 @@ interface RidingBehaviourSettings: Encodable, Decodable {
|
||||
|
||||
fun calculate(stat: RidingStat, boostAmount: Float): Float {
|
||||
val range = stats[stat] ?: return 0F
|
||||
return (range.first + boostAmount).coerceAtMost(range.endInclusive.toFloat())
|
||||
return range.first + boostAmount
|
||||
}
|
||||
}
|
||||
|
||||
-2
@@ -16,7 +16,6 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.MinekartBehaviou
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object RidingBehaviours {
|
||||
@@ -35,7 +34,6 @@ object RidingBehaviours {
|
||||
register(MinekartBehaviour.KEY, MinekartBehaviour())
|
||||
register(HoverBehaviour.KEY, HoverBehaviour())
|
||||
register(RocketBehaviour.KEY, RocketBehaviour())
|
||||
register(SubmarineBehaviour.KEY, SubmarineBehaviour())
|
||||
register(CompositeBehaviour.KEY, CompositeBehaviour())
|
||||
}
|
||||
|
||||
|
||||
+2
-13
@@ -19,7 +19,6 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import kotlin.collections.get
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import kotlin.collections.get
|
||||
|
||||
/**
|
||||
* Small wrapper around a RidingBehaviour to provide sane defaults in the event that the behaviour is not active.
|
||||
@@ -110,22 +109,12 @@ class RidingController(
|
||||
}
|
||||
|
||||
private fun canTransitionToLand(): Boolean {
|
||||
val hasLandController = entity.pokemon.riding.behaviours?.get(RidingStyle.LAND) != null
|
||||
if (hasLandController && (entity.isInLiquid || entity.isUnderWater)) return false
|
||||
if (!hasLandController && (entity.isEyeInFluid(FluidTags.WATER) || entity.isEyeInFluid(FluidTags.LAVA))) return false
|
||||
if (entity.isInLiquid || entity.isUnderWater) return false
|
||||
return entity.onGround()
|
||||
}
|
||||
|
||||
private fun canTransitionToLiquid(): Boolean {
|
||||
// If it has a liquid controller to transition to and it isn't currently an air controller then transition on
|
||||
// touching water. If not then check for eyes in water. This allows fliers to fly closely above water and
|
||||
// for walkers that don't have a liquid controller to be able to walk in not deep water
|
||||
return if (entity.pokemon.riding.behaviours?.get(RidingStyle.LIQUID) != null && context?.style != RidingStyle.AIR) {
|
||||
entity.isInLiquid || entity.isUnderWater
|
||||
} else {
|
||||
entity.isEyeInFluid(FluidTags.WATER) || entity.isEyeInFluid(FluidTags.LAVA)
|
||||
}
|
||||
|
||||
return entity.isInLiquid || entity.isUnderWater
|
||||
}
|
||||
|
||||
private fun canTransitionToAir(driver: LivingEntity?): Boolean {
|
||||
|
||||
+166
-136
@@ -34,7 +34,6 @@ 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 BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
@@ -55,7 +54,18 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
get() = CobblemonRideSettings.bird
|
||||
|
||||
override fun isActive(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
|
||||
return !(vehicle.isInWater || vehicle.isUnderWater)
|
||||
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 {
|
||||
@@ -89,8 +99,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
) {
|
||||
// Also checks stamina
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
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()))))
|
||||
@@ -109,28 +118,16 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
driver: Player
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalBird.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Grab the boost time in seconds and convert to ticks. Then calculate the drain rate as inversely
|
||||
// proportional to the number of ticks of boost thus making a full boost take x ticks
|
||||
// in short: "Stamina drains slower at higher values and also replenishes slower"
|
||||
val totalStam = vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalBird.staminaExpr!!) * 20.0f
|
||||
val horzMod = vehicle.runtime.resolveDouble(settings.stamDrainHorzMod ?: globalBird.stamDrainHorzMod!!)
|
||||
val glideMod = vehicle.runtime.resolveFloat(settings.stamDrainPercRateGlide ?: globalBird.stamDrainPercRateGlide!!)
|
||||
val stamDrainPerRateDive = vehicle.runtime.resolveDouble(settings.stamDrainPerRateDive ?: globalBird.stamDrainPerRateDive!!).coerceIn(0.0, 1.0) // Ensure its between 1 and 0 or things get weird
|
||||
val stamDrainRate = (1.0f / totalStam).toFloat()
|
||||
|
||||
val stamDrainHorz = if(vehicle.deltaMovement.horizontalDistance() < 1e-6) horzMod else max(1.0 + ((horzMod - 1.0) * atan( vehicle.deltaMovement.y / vehicle.deltaMovement.horizontalDistance())), 1.0)
|
||||
val diveAmount = sin(controller.pitch.toRadians()).coerceIn(0.0f, 1.0f)// from 0.0 -> 1.0 how steep is the current dive angle
|
||||
val diveMod = ((1.0 - diveAmount) * ( 1.0 - stamDrainPerRateDive ) + stamDrainPerRateDive).toFloat() // smooth between 1.0 and the dive drain mod depending upon how dived the ride is
|
||||
val stamDrainRate = (1.0f / totalStam).toFloat() * stamDrainHorz.toFloat()
|
||||
|
||||
val newStam = if (driver.deltaMovement.length() > 0.1) max(0.0f,stam - stamDrainRate) // Drain at normal fly rate
|
||||
else if (state.gliding.get()) min(1.0f,stam - stamDrainRate * glideMod * diveMod) // Gliding drain logic
|
||||
else max(0.0f,stam - stamDrainRate * 0.5f) // if hovering half the stam drain
|
||||
val newStam = if (driver.zza > 0.0) max(0.0f,stam - stamDrainRate)
|
||||
else if (!state.gliding.get()) max(0.0f,stam - stamDrainRate * 0.5f) // if hovering half the stam drain
|
||||
else min(1.0f,stam + stamDrainRate * 0.2f)
|
||||
|
||||
state.stamina.set(newStam)
|
||||
}
|
||||
@@ -141,7 +138,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2.ZERO//Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
@@ -151,26 +148,29 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val controller = (vehicle as? OrientationControllable)?.orientationController
|
||||
if (controller == null || controller.orientation == null) return Vec3.ZERO
|
||||
var upForce = 0.0
|
||||
var forwardForce = 0.0
|
||||
|
||||
//Perform ride velocity update
|
||||
calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
|
||||
//Translate ride space velocity to world space velocity.
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
if (controller != null) {
|
||||
//Need to deadzone this when straight up or down
|
||||
|
||||
upForce += -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
forwardForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
|
||||
upForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().y
|
||||
forwardForce += sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().y
|
||||
}
|
||||
|
||||
// The downward force used to encourage players to stop flying upside down.
|
||||
val extraDownwardForce = state.currUpsideDownForce.get().pow(2) * -0.3 // 6 blocks a second downward
|
||||
|
||||
// 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
|
||||
)
|
||||
// Unrotate preemptively as this vector gets rotatee later down the line in MC logic.
|
||||
var worldVelVec = localVelVec.mul(controller.orientation).toVec3d().yRot(vehicle.yRot.toRadians())
|
||||
worldVelVec = worldVelVec.add(0.0, extraDownwardForce, 0.0) // Add the stamina depletion force to bring the ride down.
|
||||
|
||||
return worldVelVec
|
||||
val velocity = Vec3(state.rideVelocity.get().x , upForce + extraDownwardForce, forwardForce)
|
||||
return velocity
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -191,8 +191,8 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
newVelocity = newVelocity.normalize().scale(vehicle.deltaMovement.length())
|
||||
}
|
||||
|
||||
// speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0 && newVelocity.length() < glideTopSpeed) {
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
state.stamina.get() == 0.0f -> 0.0
|
||||
@@ -209,7 +209,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
val controller = (vehicle as? OrientationControllable)?.orientationController
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
if (controller != null) {
|
||||
//Base glide speed change on current pitch of the ride.
|
||||
glideSpeedChange = sin(Math.toRadians(controller.pitch.toDouble()))
|
||||
@@ -285,13 +285,15 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
if (Cobblemon.config.disableRoll) return Vec3.ZERO
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalBird.handlingExpr!!)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0
|
||||
|
||||
val yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble()))
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble()))*2).coerceIn(-1.0, 1.0)
|
||||
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)).pow(2))
|
||||
@@ -300,13 +302,10 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
// Correct orientation when at low speeds
|
||||
correctOrientation(settings, state, vehicle, controller, deltaTime)
|
||||
|
||||
val pCorr = (state.currPitchCorrectionForce.get() * deltaTime).toFloat()
|
||||
val rCorr = (state.currRollCorrectionForce.get() * deltaTime).toFloat()
|
||||
controller.applyGlobalPitch(pCorr)
|
||||
controller.rotateRoll(rCorr)
|
||||
controller.applyGlobalPitch(state.currPitchCorrectionForce.get().toRadians())
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
return Vec3(0.0, 0.0, state.currRollCorrectionForce.get())
|
||||
}
|
||||
|
||||
private fun correctOrientation(
|
||||
@@ -317,48 +316,45 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
deltaTime: Double
|
||||
) {
|
||||
// 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 ?: globalBird.timeToRollCorrect!!)
|
||||
// If the ride is moving then have the correction rate be an equal proportion of:
|
||||
// - how rolled are you
|
||||
// - how long has it been since last mouse input (higher is stronger correction)
|
||||
// Also the correction is proportional as a whole to how NOT pitched are you so you don't spin endlessly when looking up or down
|
||||
val howRolledAmI = sqrt(abs((cos(controller.roll.toRadians()) - 1.0f) * 0.5f)) // sqrt so it trends towards one pretty quickly
|
||||
val maxRollCorrectionRate =
|
||||
if (state.rideVelocity.get().length() < 0.2) 45.0f
|
||||
else 45.0f * cos(controller.pitch.toRadians()).pow(2) * (
|
||||
howRolledAmI*1.0f +
|
||||
(state.noInputTimeRoll.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
)
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0f
|
||||
val rollArrivalDeg = 35.0f
|
||||
val desiredRoll = 0.0f
|
||||
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.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()
|
||||
|
||||
// Calculate the signed error (how far and in what direction)
|
||||
val rollError = Mth.wrapDegrees(desiredRoll.angleDifference(controller.roll))
|
||||
// Use the absolute error to calculate the magnitude of the influence
|
||||
val influenceMagnitude = (min(rollArrivalDeg, abs(rollError)) / rollArrivalDeg)
|
||||
val desiredRollForce = maxRollCorrectionRate * influenceMagnitude * -rollError.sign
|
||||
var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredRollForce) > maxRollForce) {
|
||||
steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredRollForce) > maxRollForce) {
|
||||
steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
}
|
||||
|
||||
// Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + steeredRollForce
|
||||
)
|
||||
} else {
|
||||
state.currRollCorrectionForce.set(
|
||||
//reduce rollCorrection gradually
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.96)
|
||||
)
|
||||
}
|
||||
// Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + steeredRollForce
|
||||
)
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
val maxPitchCorrectionRate = if (state.currUpsideDownForce.get() != 0.0) 15.0f * state.currUpsideDownForce.get().toFloat() else 30.0f
|
||||
val maxPitchForce = maxPitchCorrectionRate / 40.0f
|
||||
val pitchArrivalDeg = 35.0f
|
||||
val desiredPitch = if (state.currUpsideDownForce.get() != 0.0) 90.0f else 0.0f
|
||||
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) || state.currUpsideDownForce.get() != 0.0) {
|
||||
val pitchErrror = Mth.wrapDegrees(desiredPitch.angleDifference(controller.pitch))
|
||||
val arrivalInfluence = (min(pitchArrivalDeg,abs(pitchErrror)) / pitchArrivalDeg)
|
||||
val desiredPitchForce = maxPitchCorrectionRate * arrivalInfluence * -pitchErrror.sign
|
||||
var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
|
||||
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) {
|
||||
@@ -408,18 +404,80 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
state.noInputTimePitch.set(0.0)
|
||||
}
|
||||
|
||||
return rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
return when {
|
||||
Cobblemon.config.disableRoll -> noRollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
else -> rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun noRollRotation(
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalBird.handlingExpr!!)
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalBird.mouseInputMult!!)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
val mouseXc = ((mouseX).coerceIn(-60.0, 60.0) / 60.0) * mouseInputMult
|
||||
val mouseYc = ((mouseY).coerceIn(-60.0, 60.0) / 60.0) * mouseInputMult
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * handling //* ( 1.0 - min(sqrt(RidingBehaviour.scaleToRange(state.rideVelocity.get().length(), 0.0, topSpeed)), 0.5))
|
||||
|
||||
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
controller.applyGlobalYaw(yawForce.toFloat() * abs(cos(controller.pitch.toRadians())).pow(2))
|
||||
|
||||
var pitchRot = yInput * handling
|
||||
|
||||
// Pitch up globally
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
pitchRot = 0.0
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
fun rollRotation(
|
||||
@@ -434,31 +492,29 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalBird.mouseInputMult!!)
|
||||
// Applied to mouseX to prevent turning upside down when trying to roll hard.
|
||||
val rollDegreeDebuff = if(mouseX.sign.toFloat() == controller.roll.sign) 1 - 0.9f*sqrt(abs(sin(controller.roll.toRadians())))*sqrt(abs(cos(controller.pitch))) else 1.0f
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 2.0
|
||||
val mouseXc = (mouseX).coerceIn(-45.0, 45.0) * mouseInputMult * rollDegreeDebuff
|
||||
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
|
||||
val rolledOverPitchCorrection = -8*sqrt(abs(min(cos(controller.roll.toRadians()),0.0f))) * (cos(controller.pitch.toRadians())).pow(2)
|
||||
val mouseYc = ((mouseY).coerceIn(-45.0, 45.0) * mouseInputMult) + rolledOverPitchCorrection
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed)
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed)
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
val currHorzSpeed = state.rideVelocity.get().horizontalDistance()
|
||||
val hoverSpeed = 0.1
|
||||
val pitchDamping = abs(cos(controller.pitch.toRadians())).pow(2) // Helper value used when wanting to discard the influence of another value at steep pitches
|
||||
|
||||
// Yaw locally when at or below hoverSpeed but not when pitched up or rolled over
|
||||
val globalYaw = xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currHorzSpeed, hoverSpeed, topSpeed))).coerceIn(0.0, 1.0)
|
||||
controller.applyGlobalYaw(globalYaw.toFloat())
|
||||
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 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
|
||||
@@ -473,18 +529,14 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
// 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 howRolledAmI = (( cos(controller.roll.toRadians()) - 1).coerceIn(-1.0f, 0.0f) * -2) //Coerce into how much roll you want to let in in the deadzone
|
||||
val isInputtingTowardsRoll = if ( xInput.sign == controller.roll.sign.toDouble()) 1.0 else 0.0
|
||||
val inputInRolledDir = if (isInputtingTowardsRoll == 1.0) 1.0 else -cos(controller.roll.toRadians()).coerceIn(-1.0f, 0.0f).toDouble()
|
||||
val rollDampen = (1 - howRolledAmI.coerceIn(0.0f, 0.7f) * pitchDamping * inputInRolledDir)
|
||||
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
|
||||
|
||||
// When already rolled significantly part of the roll force should turn to local yaw force
|
||||
val localYawForce = rollForce * abs(sin(controller.roll.toRadians())).pow(2) * pitchDamping * isInputtingTowardsRoll
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(localYawForce, localPitch, rollForce)
|
||||
return Vec3(localYaw, localPitch, rollForce)
|
||||
}
|
||||
|
||||
|
||||
@@ -532,11 +584,11 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
driver: Player
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalBird.speedExpr!!) / 20.0
|
||||
val glideTopSpeed = topSpeed * vehicle.runtime.resolveDouble(settings.glideSpeedExpr ?: globalBird.glideSpeedExpr!!)
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
|
||||
val speedOverTopSpeed = max( 0.0, currSpeed - topSpeed)
|
||||
|
||||
val normalizedGlideSpeed = RidingBehaviour.scaleToRange(speedOverTopSpeed, 0.0, 0.3)
|
||||
// Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedGlideSpeed = RidingBehaviour.scaleToRange(currSpeed, topSpeed, glideTopSpeed)
|
||||
|
||||
// Only ever want the fov change to be a max of 0.2 and for it to have non linear scaling.
|
||||
return 1.0f + normalizedGlideSpeed.pow(2).toFloat() * 0.2f
|
||||
@@ -640,22 +692,6 @@ class BirdSettings : RidingBehaviourSettings {
|
||||
var glideSpeedExpr: Expression? = null
|
||||
private set
|
||||
|
||||
// debuff to stamina drain (increases stamina drain?) depending on how horizontal you're looking (so just drain more when climbing in altitude)
|
||||
// So for the base 1.5: If looking straight up and holding forward you drain at 150 percent the rate you would if
|
||||
// you were horizontal.
|
||||
var stamDrainHorzMod: Expression? = null
|
||||
private set
|
||||
|
||||
// long ass variable name
|
||||
// Percent of stamina drain during glide (percent of normal drain rate) So base is 25 percent. (change to 0 if you want no drain or negative if you want regen)
|
||||
var stamDrainPercRateGlide: Expression? = null
|
||||
private set
|
||||
|
||||
// Percent of stamina drain as a factor of how hard you're diving. So if its zero then at full dive you drain no stam.
|
||||
// This stacks with `stamDrainPercRateGlide`
|
||||
// This is coerced between 1 and 0 or things would get weird.
|
||||
var stamDrainPerRateDive: Expression? = null
|
||||
private set
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -670,9 +706,6 @@ class BirdSettings : RidingBehaviourSettings {
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(stamDrainHorzMod)
|
||||
buffer.writeNullableExpression(stamDrainPercRateGlide)
|
||||
buffer.writeNullableExpression(stamDrainPerRateDive)
|
||||
buffer.writeNullableExpression(timeToRollCorrect)
|
||||
}
|
||||
|
||||
@@ -688,9 +721,6 @@ class BirdSettings : RidingBehaviourSettings {
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
stamDrainHorzMod = buffer.readNullableExpression()
|
||||
stamDrainPercRateGlide = buffer.readNullableExpression()
|
||||
stamDrainPerRateDive = buffer.readNullableExpression()
|
||||
timeToRollCorrect = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
|
||||
val poseProvider = PoseProvider<HoverSettings, HoverState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption abs(state.rideVelocity.get().length()) > 0.01
|
||||
return@PoseOption abs(state.rideVelocity.get().z) > 0.2
|
||||
})
|
||||
|
||||
override fun isActive(
|
||||
|
||||
+90
-7
@@ -161,7 +161,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val controller = (vehicle as? OrientationControllable)?.orientationController
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
if (controller == null || controller.orientation == null) return Vec3.ZERO
|
||||
|
||||
//Calculate ride space velocity
|
||||
@@ -265,6 +265,8 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
//don't yaw this way if
|
||||
if (Cobblemon.config.disableRoll) return Vec3.ZERO
|
||||
|
||||
//Cap at a rate of 5fps so frame skips dont lead to huge jumps
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
@@ -296,7 +298,8 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return rollRotation(
|
||||
return when {
|
||||
Cobblemon.config.disableRoll -> noRollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
@@ -307,7 +310,78 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
)
|
||||
else -> rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun noRollRotation(
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
//Cap at a rate of 5fps so frame skips dont lead to huge jumps
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
|
||||
// Accumulate the mouse input
|
||||
state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX)).coerceIn(-1.0, 1.0))
|
||||
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY)).coerceIn(-1.0, 1.0))
|
||||
|
||||
//Get handling in degrees per second
|
||||
val handlingDebuff = if(state.stamina.get() == 0.0f) 0.5 else 1.0
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalJet.handlingExpr!!) * handlingDebuff
|
||||
//convert it to delta time
|
||||
handling *= (cappedDeltaTime)
|
||||
|
||||
var pitchRot = handling * state.currMouseYForce.get()
|
||||
|
||||
// Yaw
|
||||
val yawRot = handling * 0.5 * state.currMouseXForce.get()
|
||||
controller.applyGlobalYaw(yawRot.toFloat())
|
||||
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
pitchRot = 0.0
|
||||
state.currMouseYForce.set(0.0)
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
}
|
||||
|
||||
// Have accumulated input begin decay when no input detected
|
||||
if (abs(mouseX) == 0.0) {
|
||||
// Have decay on roll be much stronger.
|
||||
state.currMouseXForce.set(lerp(state.currMouseXForce.get(), 0.0, 0.02))
|
||||
}
|
||||
if (mouseY == 0.0) {
|
||||
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.005))
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
fun rollRotation(
|
||||
@@ -322,8 +396,9 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
//TODO: figure out a cleaner solution to this issue of large jumps when skipping frames or lagging
|
||||
//Cap at a rate of 5fps so frame skips dont lead to huge jumps
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
|
||||
// Accumulate the mouse input
|
||||
@@ -337,6 +412,14 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
//convert it to delta time
|
||||
handling *= (cappedDeltaTime)
|
||||
|
||||
|
||||
val poke = driver.vehicle as? PokemonEntity
|
||||
|
||||
//TODO: reevaluate if deadzones are needed and if they are still causing issues.
|
||||
//create deadzones for the constant input values.
|
||||
//val xInput = remapWithDeadzone(state.currMouseXForce, 0.025, 1.0)
|
||||
//val yInput = remapWithDeadzone(state.currMouseYForce, 0.025, 1.0)
|
||||
|
||||
val pitchRot = handling * state.currMouseYForce.get()
|
||||
|
||||
// Roll
|
||||
@@ -347,10 +430,10 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
// Have accumulated input begin decay when no input detected
|
||||
if (abs(mouseX) == 0.0) {
|
||||
// Have decay on roll be much stronger.
|
||||
state.currMouseXForce.set(lerp(state.currMouseXForce.get(), 0.0, 0.08))
|
||||
state.currMouseXForce.set(lerp(state.currMouseXForce.get(), 0.0, 0.02))
|
||||
}
|
||||
if (mouseY == 0.0) {
|
||||
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.02))
|
||||
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.005))
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
|
||||
+13
-18
@@ -103,12 +103,12 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
|
||||
if (!state.isVehicleSprinting.get()) {
|
||||
if (state.staminaBuffer.get() >= 20) {
|
||||
val staminaIncrease = (1.0f / vehicle.runtime.resolveDouble(settings.stamReplenishTimeSeconds ?: globalBoat.stamReplenishTimeSeconds!!) ).toFloat() / 20.0f
|
||||
state.stamina.set(min(1.0f, state.stamina.get() + staminaIncrease))
|
||||
val staminaIncrease = vehicle.runtime.resolveDouble(settings.staminaIncreaseExpr ?: globalBoat.staminaIncreaseExpr!!)
|
||||
state.stamina.set(min(1.0f, state.stamina.get() + 0.01f * staminaIncrease.toFloat()))
|
||||
}
|
||||
}
|
||||
else if (abs(state.rideVelocity.get().z) > 0.1 && state.isVehicleSprinting.get()) {
|
||||
consumeStamina(vehicle, driver, settings, state)
|
||||
consumeStamina(vehicle, driver, settings, state, 0.01f)
|
||||
}
|
||||
state.staminaBuffer.set(state.staminaBuffer.get() + 1)
|
||||
super.tick(settings, state, vehicle, driver, input)
|
||||
@@ -219,12 +219,12 @@ class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
return state.stamina.get() != 0f
|
||||
}
|
||||
|
||||
private fun consumeStamina(vehicle: PokemonEntity, driver: Player, settings: BoatSettings, state: BoatState) {
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalBoat.infiniteStamina!!)) {
|
||||
private fun consumeStamina(vehicle: PokemonEntity, driver: Player, settings: BoatSettings, state: BoatState, drain: Float) {
|
||||
val staminaModifier = vehicle.runtime.resolveFloat(settings.staminaDecreaseExpr ?: globalBoat.staminaDecreaseExpr!!)
|
||||
if (staminaModifier == 0F) {
|
||||
return
|
||||
}
|
||||
val stamDrainRate = (1.0f / vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalBoat.staminaExpr!!)).toFloat() / 20.0f
|
||||
state.stamina.set(max(0f, state.stamina.get() - stamDrainRate))
|
||||
state.stamina.set(max(0f, state.stamina.get() - drain / staminaModifier))
|
||||
if (state.stamina.get() == 0f) {
|
||||
state.isVehicleSprinting.set(false)
|
||||
driver.isSprinting = false
|
||||
@@ -404,19 +404,16 @@ class BoatSettings : RidingBehaviourSettings {
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
var terminalVelocity: Expression? = null
|
||||
private set
|
||||
|
||||
var rotatePokemonHead: Expression? = null
|
||||
private set
|
||||
|
||||
var stamReplenishTimeSeconds: Expression? = null
|
||||
var staminaIncreaseExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var staminaExpr: Expression? = null
|
||||
var staminaDecreaseExpr: Expression? = null
|
||||
private set
|
||||
|
||||
var rotationSpeedModifierExpr: Expression? = null
|
||||
@@ -441,11 +438,10 @@ class BoatSettings : RidingBehaviourSettings {
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(terminalVelocity)
|
||||
buffer.writeNullableExpression(rotatePokemonHead)
|
||||
buffer.writeNullableExpression(stamReplenishTimeSeconds)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
buffer.writeNullableExpression(staminaIncreaseExpr)
|
||||
buffer.writeNullableExpression(staminaDecreaseExpr)
|
||||
buffer.writeNullableExpression(rotationSpeedModifierExpr)
|
||||
buffer.writeNullableExpression(jumpStrengthExpr)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
@@ -458,11 +454,10 @@ class BoatSettings : RidingBehaviourSettings {
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
terminalVelocity = buffer.readNullableExpression()
|
||||
rotatePokemonHead = buffer.readNullableExpression()
|
||||
stamReplenishTimeSeconds = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
staminaIncreaseExpr = buffer.readNullableExpression()
|
||||
staminaDecreaseExpr = buffer.readNullableExpression()
|
||||
rotationSpeedModifierExpr = buffer.readNullableExpression()
|
||||
jumpStrengthExpr = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
|
||||
+160
-157
@@ -20,7 +20,6 @@ import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.Side
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.ridingState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.angleDifference
|
||||
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
|
||||
@@ -48,7 +47,6 @@ 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 org.joml.Vector3f
|
||||
|
||||
class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
companion object {
|
||||
@@ -64,7 +62,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<DolphinSettings, DolphinState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, state, entity -> abs(state.rideVelocity.get().length()) > 0.05 })
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.deltaMovement.length() > 0.1 })
|
||||
|
||||
override fun isActive(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Boolean {
|
||||
return vehicle.isInWater || !vehicle.onGround()
|
||||
@@ -153,46 +151,37 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
val orientation = controller.orientation ?: return Vec3.ZERO
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val runtime = vehicle.runtime
|
||||
val boostMod = if (state.boosting.get()) runtime.resolveDouble(settings.jumpExpr ?: globalDolphin.jumpExpr!!) else 1.0
|
||||
val topSpeed = (vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.speedExpr!!) / 20.0) * boostMod
|
||||
val accel = (topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalDolphin.accelerationExpr!!) * 20.0)) * boostMod
|
||||
val strafeFactor = runtime.resolveDouble(settings.strafeFactor ?: globalDolphin.strafeFactor!!)
|
||||
val reverseDriveFactor = runtime.resolveDouble(settings.reverseDriveFactor ?: globalDolphin.reverseDriveFactor!!)
|
||||
var currVel = state.rideVelocity.get()
|
||||
|
||||
/*********************************************
|
||||
* Breaching logic
|
||||
*********************************************/
|
||||
if (!vehicle.isInWater && !vehicle.isUnderWater)
|
||||
{
|
||||
var prevVel = state.lastVelocity.get()
|
||||
val breachBoost = 0.3
|
||||
state.clearMouseSmoothers.set(false)
|
||||
val currVel = state.lastVelocity.get()
|
||||
val breachBoost = 1.5
|
||||
if (!state.hasBreached.get()) {
|
||||
// Apply an upwards breaching force if boosting. This will enhance jumping out of water to feel more fun
|
||||
// Apply an upwards breaching force if boosting. This will enhance jumping out of water to feel more
|
||||
// fun
|
||||
if (state.boosting.get()) {
|
||||
prevVel = Vec3(prevVel.x, prevVel.y + breachBoost*(sin(-controller.pitch.toRadians()).coerceIn(0.0f,0.5f)*2.0).pow(2), prevVel.z)
|
||||
state.lastVelocity.set(Vec3(currVel.x, currVel.y + breachBoost*sin(-controller.pitch.toRadians()).coerceIn(0.0f,0.5f), currVel.z))
|
||||
}
|
||||
state.hasBreached.set(true)
|
||||
} else {
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.4
|
||||
val terminalVel = 2.0
|
||||
prevVel = Vec3(prevVel.x, max(-terminalVel, prevVel.y - gravity), prevVel.z)
|
||||
state.lastVelocity.set(Vec3(currVel.x, max(-terminalVel, currVel.y - gravity), currVel.z)) //.yRot(vehicle.yRot.toRadians()))
|
||||
}
|
||||
|
||||
state.lastVelocity.set(prevVel)
|
||||
return state.lastVelocity.get().yRot(vehicle.yRot.toRadians())
|
||||
return state.lastVelocity.get()
|
||||
} else {
|
||||
if(state.hasBreached.get()) {
|
||||
state.clearMouseSmoothers.set(true)
|
||||
}
|
||||
state.lastVelocity.set(vehicle.deltaMovement.yRot(vehicle.yRot.toRadians()))
|
||||
state.hasBreached.set(false)
|
||||
currVel = Vec3(currVel.x, 0.0, currVel.z) // Reset y velocity to account for y vel persistance edgecase
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
@@ -201,30 +190,32 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
if (vehicle.horizontalCollision || vehicle.verticalCollision) {
|
||||
// not actually friction
|
||||
val frictionLimit = 0.1
|
||||
val postColSpeed = min(max(state.rideVelocity.get().length(), frictionLimit), state.speed.get())
|
||||
val postColSpeed = min(max(vehicle.deltaMovement.length(), frictionLimit), state.speed.get())
|
||||
state.speed.set(postColSpeed)
|
||||
}
|
||||
|
||||
val currZVel = state.rideVelocity.get().z
|
||||
val newZVel = when {
|
||||
driver.zza > 0.0 -> min(topSpeed, currZVel + accel)
|
||||
driver.zza < 0.0 -> max( -topSpeed * reverseDriveFactor, currZVel - accel)
|
||||
else -> lerp(currZVel, 0.0, 0.05)
|
||||
val currSpeed = state.speed.get()
|
||||
val strafeFactor = runtime.resolveDouble(settings.strafeFactor ?: globalDolphin.strafeFactor!!)
|
||||
val reverseDriveFactor = runtime.resolveDouble(settings.reverseDriveFactor ?: globalDolphin.reverseDriveFactor!!)
|
||||
val f = -driver.xxa * strafeFactor
|
||||
when {
|
||||
driver.zza > 0.0 -> state.speed.set(min(topSpeed, currSpeed + accel))
|
||||
driver.zza < 0.0 -> state.speed.set(max( -topSpeed * reverseDriveFactor, currSpeed - accel))
|
||||
else -> state.speed.set( lerp(currSpeed, 0.0, 0.05))
|
||||
}
|
||||
state.rideVelocity.set(Vec3(currVel.x, currVel.y, newZVel))
|
||||
val vertInput = when {
|
||||
driver.jumping && state.stamina.get() != 0.0f -> 1.0
|
||||
driver.isShiftKeyDown -> -1.0
|
||||
else -> 0.0
|
||||
} * strafeFactor
|
||||
|
||||
// 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
|
||||
)
|
||||
var newVelocity = Vec3(f, vertInput,-state.speed.get())
|
||||
|
||||
val worldVelVec = localVelVec.mul(orientation).toVec3d()
|
||||
state.lastVelocity.set(worldVelVec) // Set last velocity to be used during breaching
|
||||
|
||||
// Unrotate preemptively as this vector gets rotated later down the line in MC logic.
|
||||
return worldVelVec.yRot(vehicle.yRot.toRadians())
|
||||
// Align to the ride
|
||||
newVelocity = controller.orientation?.transform(newVelocity.toVector3f())?.toVec3d() ?: Vec3.ZERO
|
||||
newVelocity = newVelocity.yRot(vehicle.yRot.toRadians())
|
||||
val desiredVec = newVelocity.subtract(vehicle.deltaMovement)
|
||||
return vehicle.deltaMovement.add(desiredVec)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
@@ -234,8 +225,9 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
if (Cobblemon.config.disableRoll) return Vec3.ZERO
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val currSpeed = vehicle.deltaMovement.length()
|
||||
|
||||
@@ -243,7 +235,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.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()))*2).coerceIn(-1.0, 1.0) * sqrt(RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble()))) * sqrt(RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))
|
||||
|
||||
// Dampen yaw when upside down
|
||||
val yawDampen = (1 - abs(min(cos(controller.roll.toRadians()),0.0f)))
|
||||
@@ -264,62 +256,45 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
) {
|
||||
// Stop roll and pitch correction when breached
|
||||
if (state.hasBreached.get()) {
|
||||
state.currRollCorrectionForce.set(
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
)
|
||||
state.currPitchCorrectionForce.set(
|
||||
lerp(state.currPitchCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate correcting roll force.
|
||||
// Mult by cos(pitch) to ensure that it doesn't roll correct at when diving or climbing
|
||||
val currSpeed = vehicle.deltaMovement.length()
|
||||
val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalDolphin.timeToRollCorrect!!)
|
||||
// If the ride is moving then have the correction rate be an equal proportion of:
|
||||
// - how rolled are you
|
||||
// - how long has it been since last mouse input (higher is stronger correction)
|
||||
// Also the correction is proportional as a whole to how NOT pitched are you so you don't spin endlessly when looking up or down
|
||||
val howRolledAmI = sqrt(abs((cos(controller.roll.toRadians()) - 1.0f) * 0.5f)) // sqrt so it trends towards one pretty quickly
|
||||
val maxRollCorrectionRate =
|
||||
if (state.rideVelocity.get().length() < 0.2) 10.0f * abs(cos(controller.pitch.toRadians()))
|
||||
else 10.0f * cos(controller.pitch.toRadians()).pow(2) * (
|
||||
howRolledAmI*1.0f +
|
||||
(state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
)
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0f
|
||||
val rollArrivalDeg = 60.0f
|
||||
val desiredRoll = 0.0f
|
||||
val maxRollCorrectionRate = if (!(vehicle.isInWater || vehicle.isUnderWater)) 15.0f
|
||||
else 10.0f * (cos(controller.pitch.toRadians())).pow(2) * ((state.noInputTime.get() - rollCorrectionTimer) * 2).coerceIn(0.0, 1.0).toFloat()
|
||||
val maxRollForce = maxRollCorrectionRate / 40.0
|
||||
val rollArrivalDeg = 90.0
|
||||
|
||||
// Calculate the signed error (how far and in what direction)
|
||||
val rollError = Mth.wrapDegrees(desiredRoll.angleDifference(controller.roll))
|
||||
if((state.speed.get() < 0.1 && driver.zza.toDouble() == 0.0) || state.noInputTime.get() > rollCorrectionTimer || !(vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
val arrivalInfluence = (min(rollArrivalDeg,abs(controller.roll).toDouble()) / rollArrivalDeg)
|
||||
val desiredRollForce = (0 - controller.roll).sign * maxRollCorrectionRate * arrivalInfluence
|
||||
var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
|
||||
// Use the absolute error to calculate the magnitude of the influence
|
||||
val influenceMagnitude = (min(rollArrivalDeg, abs(rollError)) / rollArrivalDeg)
|
||||
val desiredRollForce = maxRollCorrectionRate * influenceMagnitude * -rollError.sign
|
||||
var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredRollForce) > maxRollForce) {
|
||||
steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
}
|
||||
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
if (abs(steeredRollForce) > maxRollForce) {
|
||||
steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
// Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + steeredRollForce
|
||||
)
|
||||
} else {
|
||||
state.currRollCorrectionForce.set(
|
||||
//reduce rollCorrection gradually
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.96)
|
||||
)
|
||||
}
|
||||
|
||||
// Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + steeredRollForce
|
||||
)
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
val maxPitchCorrectionRate = 5.0f * (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
val maxPitchForce = maxPitchCorrectionRate / 40.0f
|
||||
val pitchArrivalDeg = 45.0f
|
||||
val desiredPitch = 0.0f
|
||||
val maxPitchCorrectionRate = if (!(vehicle.isInWater || vehicle.isUnderWater)) 15.0 else 5.0f * ((state.noInputTime.get() - rollCorrectionTimer) * 2).coerceIn(0.0, 1.0).toFloat() * (1 - (currSpeed * 0.5).coerceIn(0.0, 1.0))
|
||||
val maxPitchForce = maxPitchCorrectionRate / 40.0
|
||||
val pitchArrivalDeg = 45.0
|
||||
val targetPitch = if ((vehicle.isInWater || vehicle.isUnderWater)) 0.0f else (-asin(vehicle.deltaMovement.y / vehicle.deltaMovement.length()).toDegrees()).coerceIn(-45.0f, 45.0f)
|
||||
|
||||
if(state.rideVelocity.get().length() < 0.1 && state.noInputTime.get() > rollCorrectionTimer) {
|
||||
val pitchErrror = Mth.wrapDegrees(desiredPitch.angleDifference(controller.pitch))
|
||||
val arrivalInfluence = (min(pitchArrivalDeg,abs(pitchErrror)) / pitchArrivalDeg)
|
||||
val desiredPitchForce = maxPitchCorrectionRate * arrivalInfluence * -pitchErrror.sign
|
||||
if((state.noInputTime.get() > rollCorrectionTimer && driver.zza.toDouble() == 0.0) || !(vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
val arrivalInfluence = min(rollArrivalDeg, abs(Mth.wrapDegrees(targetPitch - controller.pitch.toDouble()))) / pitchArrivalDeg
|
||||
val desiredPitchForce = (targetPitch - controller.pitch).sign * maxPitchCorrectionRate * arrivalInfluence
|
||||
var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
|
||||
|
||||
// Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
@@ -358,18 +333,81 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
} else {
|
||||
state.noInputTime.set(0.0)
|
||||
}
|
||||
return rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
return when {
|
||||
Cobblemon.config.disableRoll -> noRollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
else -> rollRotation(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun noRollRotation(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
val boostingHandleDebuff = if (state.boosting.get()) 0.2 else 1.0
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalDolphin.handlingExpr!!) * boostingHandleDebuff
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalDolphin.mouseInputMult!!)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
val mouseXc = ((mouseX).coerceIn(-60.0, 60.0) / 60.0) * mouseInputMult
|
||||
val mouseYc = ((mouseY).coerceIn(-60.0, 60.0) / 60.0) * mouseInputMult
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * handling
|
||||
|
||||
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
controller.applyGlobalYaw(yawForce.toFloat() * abs(cos(controller.pitch.toRadians())).pow(2))
|
||||
|
||||
var pitchRot = yInput * handling
|
||||
|
||||
// Pitch up globally
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
pitchRot = 0.0
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
fun rollRotation(
|
||||
@@ -384,71 +422,41 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr ?: globalDolphin.speedExpr!!) / 20.0
|
||||
val boostingHandleDebuff = if (state.boosting.get()) 0.5 else 1.0
|
||||
val boostingHandleDebuff = if (state.boosting.get()) 0.2 else 1.0
|
||||
val mouseInputMult = vehicle.runtime.resolveDouble(settings.mouseInputMult ?: globalDolphin.mouseInputMult!!) * boostingHandleDebuff
|
||||
// Applied to mouseX to prevent turning upside down when trying to roll hard.
|
||||
val rollDegreeDebuff = if(mouseX.sign.toFloat() == controller.roll.sign) 1 - 0.9f*sqrt(abs(sin(controller.roll.toRadians())))*sqrt(abs(cos(controller.pitch))) else 1.0f
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = if(state.hasBreached.get()) 1.0f else 2.0f
|
||||
// When upside down apply a pitching force to nudge the player towards a dive. This reduces the 'weirdness'
|
||||
// of being upside down
|
||||
val rolledOverPitchCorrection = -8*sqrt(abs(min(cos(controller.roll.toRadians()),0.0f))) * (cos(controller.pitch.toRadians())).pow(2)
|
||||
val mouseXc = (mouseX).coerceIn(-45.0, 45.0) * mouseInputMult * rollDegreeDebuff
|
||||
val mouseYc = (mouseY).coerceIn(-45.0, 45.0) * mouseInputMult + rolledOverPitchCorrection
|
||||
val mouseModForce = if (state.hasBreached.get()) 0.15 else 0.1 // Used to effect more spin momentum during breaching
|
||||
val smoothingSpeed = 4.0
|
||||
val mouseXc = (mouseX).coerceIn(-45.0, 45.0) * mouseInputMult
|
||||
val mouseYc = (mouseY).coerceIn(-45.0, 45.0) * mouseInputMult
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1, deltaTime * smoothingSpeed);
|
||||
val currSpeed = vehicle.deltaMovement.length()
|
||||
|
||||
if (state.clearMouseSmoothers.get()) {
|
||||
mouseXSmoother.reset()
|
||||
mouseYSmoother.reset()
|
||||
state.clearMouseSmoothers.set(false)
|
||||
}
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * mouseModForce, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * mouseModForce, deltaTime * smoothingSpeed);
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
val currHorzSpeed = state.rideVelocity.get().horizontalDistance()
|
||||
val hoverSpeed = 0.2
|
||||
val pitchDamping = abs(cos(controller.pitch.toRadians())).pow(2) // Helper value used when wanting to discard the influence of another value at steep pitches
|
||||
|
||||
// Yaw locally when at or below hoverSpeed but not when pitched up or rolled over
|
||||
val globalYaw = xInput * (1 - sqrt(RidingBehaviour.scaleToRange(currSpeed, 0.0, hoverSpeed))).coerceIn(0.0, 1.0)
|
||||
controller.rotateYaw(pitchDamping*globalYaw.toFloat())
|
||||
controller.rotateRoll((1-pitchDamping)*globalYaw.toFloat())
|
||||
// Yaw locally
|
||||
// Dampen yaw when rolled or pitched substantially
|
||||
val yawDampen = abs(cos(controller.pitch.toRadians())).pow(2) * abs(cos(controller.roll.toRadians())).pow(2)
|
||||
val localYaw = xInput * (1 - (RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))).coerceIn(0.4, 1.0) * 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
|
||||
// - Do not pitch at all when at or below hover speed
|
||||
// - pitch faster at higher speeds
|
||||
val p = 1.0 - vehicle.runtime.resolveDouble(settings.horizontalPitchExpr ?: globalDolphin.horizontalPitchExpr!!)
|
||||
val localPitch = yInput * (1 - abs(sin(controller.roll.toRadians())).pow(2) * p * hypot(controller.forwardVector.x.toDouble(), controller.forwardVector.z.toDouble()).toFloat())
|
||||
|
||||
var localYawForce = 0.0
|
||||
var rollForce = 0.0
|
||||
|
||||
// If it has breached then turn the yaw into roll
|
||||
if (state.hasBreached.get()) {
|
||||
localYawForce = xInput
|
||||
} else {
|
||||
// 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 howRolledAmI = (( cos(controller.roll.toRadians()) - 1).coerceIn(-1.0f, 0.0f) * -2) //Coerce into how much roll you want to let in in the deadzone
|
||||
val isInputtingTowardsRoll = if ( xInput.sign == controller.roll.sign.toDouble()) 1.0 else 0.0
|
||||
val inputInRolledDir = if (isInputtingTowardsRoll == 1.0) 1.0 else -cos(controller.roll.toRadians()).coerceIn(-1.0f, 0.0f).toDouble()
|
||||
val rollDampen = (1 - howRolledAmI.coerceIn(0.0f, 0.5f) * pitchDamping * inputInRolledDir)
|
||||
rollForce = xInput * sqrt(abs(RidingBehaviour.scaleToRange(currHorzSpeed, 0.0, topSpeed)).coerceIn(0.0,1.0)) * rollDampen + pitchInfluencedRollCorrection
|
||||
|
||||
// When already rolled significantly part of the roll force should turn to local yaw force
|
||||
localYawForce = rollForce * abs(sin(controller.roll.toRadians())).pow(2) * pitchDamping * isInputtingTowardsRoll
|
||||
}
|
||||
val localPitch = yInput * (1 - abs(sin(controller.roll.toRadians())) * p * hypot(controller.forwardVector.x.toDouble(), controller.forwardVector.z.toDouble()).toFloat())
|
||||
// localPitch *= if (currSpeed > hoverSpeed) RidingBehaviour.scaleToRange(currSpeed, hoverSpeed, topSpeed)
|
||||
// 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 rollForce = xInput * ((RidingBehaviour.scaleToRange(currSpeed, 0.0, topSpeed))).coerceIn(0.2, 1.0) //+ pitchInfluencedRollCorrection
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(localYawForce, localPitch, rollForce)
|
||||
return Vec3(localYaw, localPitch, rollForce)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
@@ -595,7 +603,6 @@ class DolphinSettings : RidingBehaviourSettings {
|
||||
buffer.writeNullableExpression(canJump)
|
||||
buffer.writeNullableExpression(reverseDriveFactor)
|
||||
buffer.writeNullableExpression(strafeFactor)
|
||||
buffer.writeNullableExpression(timeToRollCorrect)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(horizontalPitchExpr)
|
||||
@@ -612,7 +619,6 @@ class DolphinSettings : RidingBehaviourSettings {
|
||||
canJump = buffer.readNullableExpression()
|
||||
reverseDriveFactor = buffer.readNullableExpression()
|
||||
strafeFactor = buffer.readNullableExpression()
|
||||
timeToRollCorrect = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
horizontalPitchExpr = buffer.readNullableExpression()
|
||||
@@ -632,7 +638,6 @@ class DolphinState : RidingBehaviourState() {
|
||||
var boostIsToggleable = ridingState(false, Side.CLIENT)
|
||||
var speed = ridingState(0.0, Side.CLIENT)
|
||||
var hasBreached = ridingState(false, Side.CLIENT)
|
||||
var clearMouseSmoothers = ridingState(false, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
@@ -654,7 +659,6 @@ class DolphinState : RidingBehaviourState() {
|
||||
boostIsToggleable.set(true, forced = true)
|
||||
speed.set(0.0, forced = true)
|
||||
hasBreached.set(false, forced = true)
|
||||
clearMouseSmoothers.set(false, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
@@ -672,7 +676,6 @@ class DolphinState : RidingBehaviourState() {
|
||||
it.boostIsToggleable.set(this.boosting.get(), forced = true)
|
||||
it.speed.set(this.speed.get(), forced = true)
|
||||
it.hasBreached.set(this.hasBreached.get(), forced = true)
|
||||
it.clearMouseSmoothers.set(this.clearMouseSmoothers.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
|
||||
-643
@@ -1,643 +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.riding.behaviour.types.liquid
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
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
|
||||
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.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.readNullableExpression
|
||||
import com.cobblemon.mod.common.util.readRidingStats
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.cobblemon.mod.common.util.writeNullableExpression
|
||||
import com.cobblemon.mod.common.util.writeRidingStats
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.tags.FluidTags
|
||||
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 org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class SubmarineBehaviour : RidingBehaviour<SubmarineSettings, SubmarineState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("liquid/submarine")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
val globalSubmarine: SubmarineSettings
|
||||
get() = CobblemonRideSettings.submarine
|
||||
|
||||
override fun getRidingStyle(settings: SubmarineSettings, state: SubmarineState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<SubmarineSettings, SubmarineState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, state, entity -> state.rideVelocity.get().z > 0.05 && !state.onSurface.get()})
|
||||
.with(PoseOption(PoseType.STAND) { _, state, entity -> state.rideVelocity.get().z <= 0.05 && state.onSurface.get()})
|
||||
.with(PoseOption(PoseType.STAND) { _, state, entity -> state.rideVelocity.get().z > 0.05 && state.onSurface.get()})
|
||||
|
||||
override fun isActive(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return vehicle.isInWater || !vehicle.onGround()
|
||||
}
|
||||
|
||||
override fun pose(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return state.speed.get().toFloat()
|
||||
}
|
||||
|
||||
override fun tick(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
) {
|
||||
if(vehicle.level().isClientSide) {
|
||||
tickStamina(settings, state, vehicle)
|
||||
surfaceCheck(settings, state, vehicle, driver)
|
||||
}
|
||||
}
|
||||
|
||||
fun tickStamina(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity
|
||||
) {
|
||||
val stam = state.stamina.get()
|
||||
|
||||
if (vehicle.runtime.resolveBoolean(settings.infiniteStamina ?: globalSubmarine.infiniteStamina!!)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Grab the boost time in seconds and convert to ticks. Then calculate the drain rate as inversely
|
||||
// proportional to the number of ticks of boost thus making a full boost take x ticks
|
||||
// in short: "Stamina drains slower at higher values and also replenishes slower"
|
||||
val breathTime = vehicle.runtime.resolveDouble(settings.staminaExpr ?: globalSubmarine.staminaExpr!!) * 20.0f
|
||||
val stamRegenRate = 1.0f / (vehicle.runtime.resolveDouble(settings.staminaRegenTime ?: globalSubmarine.staminaRegenTime!!).toFloat() * 20.0f)
|
||||
val stamDrainRate = (1.0f / breathTime).toFloat()
|
||||
val driver = vehicle.controllingPassenger
|
||||
val newStam = if (driver?.isEyeInFluid(FluidTags.WATER) ?: false) max(0.0f,stam - stamDrainRate)
|
||||
else min(1.0f,stam + stamRegenRate)
|
||||
|
||||
state.stamina.set(newStam)
|
||||
}
|
||||
|
||||
private fun surfaceCheck(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
) {
|
||||
// determine if the vehicle is in water.
|
||||
// if it isn't then set surface flag to false and return
|
||||
if (!vehicle.isInWater) {
|
||||
state.onSurface.set(false)
|
||||
return
|
||||
}
|
||||
|
||||
// if it is then check half the bbheight above and below the center point.
|
||||
|
||||
// If the point above is air and the point below is water then you know to trend towards on surface.
|
||||
|
||||
// Grab the center position of the vehicle (vehicle.position.add(bbheight/2)
|
||||
val vehicleCenter = vehicle.position().add(0.0, vehicle.bbHeight/2.0, 0.0)
|
||||
|
||||
// If the block above the center is not fluid but this one is then move the center
|
||||
val centerBlockPos = BlockPos.containing(vehicleCenter)
|
||||
val centerInWater = !vehicle.level().getFluidState(centerBlockPos).isEmpty
|
||||
|
||||
val abovePos = centerBlockPos.above()
|
||||
val aboveInWater = !vehicle.level().getFluidState(abovePos).isEmpty
|
||||
|
||||
if (!centerInWater && !aboveInWater) {
|
||||
state.onSurface.set(true)
|
||||
} else {
|
||||
state.onSurface.set(false)
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// Function for if x mouse and y mouse "get through" to affecting the mounts rotation. Return a Pair<Boolean, Boolean>
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
val orientation = controller.orientation ?: return Vec3.ZERO
|
||||
|
||||
val runtime = vehicle.runtime
|
||||
val topSpeed = (vehicle.runtime.resolveDouble(settings.speedExpr ?: globalSubmarine.speedExpr!!) / 20.0)
|
||||
val accel = (topSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalSubmarine.accelerationExpr!!) * 20.0))
|
||||
val strafeSpeed = (runtime.resolveDouble(settings.jumpExpr ?: globalSubmarine.jumpExpr!!) / 20.0)
|
||||
val strafeAccel = (strafeSpeed / (vehicle.runtime.resolveDouble(settings.accelerationExpr ?: globalSubmarine.accelerationExpr!!) * 20.0))
|
||||
var currVel = state.rideVelocity.get()
|
||||
|
||||
/*********************************************
|
||||
* Handle collisions
|
||||
*********************************************/
|
||||
if (vehicle.horizontalCollision || vehicle.verticalCollision) {
|
||||
// not actually friction
|
||||
val frictionLimit = 0.1
|
||||
val postColSpeed = min(max(state.rideVelocity.get().length(), frictionLimit), state.speed.get())
|
||||
state.speed.set(postColSpeed)
|
||||
}
|
||||
if (vehicle.verticalCollision) {
|
||||
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, 0.0, state.rideVelocity.get().z))
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* Calculate Forward Velocity
|
||||
*********************************************/
|
||||
val currZVel = state.rideVelocity.get().z
|
||||
val newZVel = when {
|
||||
driver.zza > 0.0 -> min(topSpeed, currZVel + accel)
|
||||
driver.zza < 0.0 -> max( -strafeSpeed, currZVel - strafeAccel) //TODO: Might need to be applied in addition to the normal braking force?
|
||||
else -> lerp(currZVel, 0.0, 0.05)
|
||||
}
|
||||
currVel = Vec3(currVel.x, currVel.y, newZVel)
|
||||
|
||||
/*********************************************
|
||||
* Calculate up/down Velocity and gravity
|
||||
*********************************************/
|
||||
val vertTopSpeed = strafeSpeed
|
||||
val currYVel = state.rideVelocity.get().y
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.4
|
||||
val terminalYVel = 2.0
|
||||
val driverYInput = if(driver.jumping) 1.0 else if (driver.isShiftKeyDown) -1.0 else 0.0
|
||||
val newYVel = when {
|
||||
(!vehicle.isInWater) -> max(-terminalYVel, currYVel - gravity)
|
||||
//(vehicle.isInWater && !vehicle.isUnderWater && currYVel > 0.001) -> lerp(currYVel, 0.0, 0.1) // Make sure that yVel is above a threshold before doing this otherwise it'll block submerging.
|
||||
//driverYInput != 0.0 && currYVel > 0.001 && driverYInput.sign != currYVel.sign -> lerp(currYVel, 0.0, 0.05)
|
||||
driverYInput > 0.0 -> min(vertTopSpeed, currYVel + strafeAccel)
|
||||
driverYInput < 0.0 -> max(-vertTopSpeed, currYVel - strafeAccel)
|
||||
else -> lerp(currYVel, 0.0, 0.05)
|
||||
}
|
||||
currVel = Vec3(currVel.x, newYVel, currVel.z)
|
||||
|
||||
/*********************************************
|
||||
* Calculate left/right strafing Velocity
|
||||
*********************************************/
|
||||
val currXVel = state.rideVelocity.get().x
|
||||
val horzTopSpeed = strafeSpeed
|
||||
val newXVel = when {
|
||||
driver.xxa > 0.0 -> min(horzTopSpeed, currXVel + strafeAccel)
|
||||
driver.xxa < 0.0 -> max( -horzTopSpeed, currXVel - strafeAccel)
|
||||
else -> lerp(currXVel, 0.0, 0.01)
|
||||
}
|
||||
currVel = Vec3(newXVel, currVel.y, currVel.z)
|
||||
|
||||
// Set the new velocity
|
||||
state.rideVelocity.set(currVel)
|
||||
|
||||
/*********************************************
|
||||
* Separate and apply velocities
|
||||
*********************************************/
|
||||
// If the driver and vehicles eyes are out of the water but the vehicle is still in it then move only horizontally or downwards as you have surfaced
|
||||
if (state.onSurface.get()) {
|
||||
val worldVelVec = Vec3(currVel.x, min(0.0, currVel.y), currVel.z)
|
||||
return worldVelVec
|
||||
} else {
|
||||
val vertVec = Vec3(0.0, currVel.y, 0.0)
|
||||
val horzVec = Vec3(currVel.x, 0.0, 0.0)
|
||||
val localZVelVec = Vector3f(0.0f, 0.0f, currVel.z.toFloat() * -1.0f) // Flip the z axis to make this left handed
|
||||
// Unrotate preemptively as this vector gets rotated later down the line in MC logic.
|
||||
val worldVelVec = localZVelVec.mul(orientation).toVec3d().yRot(vehicle.yRot.toRadians())
|
||||
// Add back the horizontal and vertical components.
|
||||
return worldVelVec.add(vertVec).add(horzVec)
|
||||
}
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun applyRenderRotation(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
partialTicks: Float
|
||||
) {
|
||||
if (vehicle !is OrientationControllable) return
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalSubmarine.handlingExpr!!)
|
||||
val surfaceHandlingBoost = if(state.onSurface.get()) 3.0 else 1.0
|
||||
handling *= surfaceHandlingBoost
|
||||
|
||||
val strafeSpeed = (vehicle.runtime.resolveDouble(settings.jumpExpr ?: globalSubmarine.jumpExpr!!) / 20.0)
|
||||
|
||||
// Grab the roll and see if its hit the limit yet. If it hasn't then trend it towards its desired roll
|
||||
val maxRollDeg = if (state.onSurface.get()) 5 else 15
|
||||
val maxPitchDeg = 15
|
||||
var rollAmount = 0.0
|
||||
var pitchAmount = 0.0
|
||||
|
||||
// Do horizontal speed based rolling
|
||||
val maxHorzSpeed = strafeSpeed
|
||||
val currHorzSpeed = state.rideVelocity.get().x
|
||||
var desiredRoll = -(currHorzSpeed / maxHorzSpeed).coerceIn(-1.0, 1.0) * maxRollDeg
|
||||
rollAmount += lerp(controller.roll.toDouble(), desiredRoll, partialTicks.toDouble()) - controller.roll
|
||||
//val rotAmount //Maybe use some lerp?
|
||||
controller.rotateRoll(rollAmount.toFloat())
|
||||
|
||||
// Do yawRate based rolling
|
||||
val maxYawRate = handling
|
||||
val currYawRate = vehicle.ridingAnimationData.rotDeltaSpring.getInterpolated(partialTicks.toDouble(), 2).y()
|
||||
desiredRoll = -(currYawRate / maxYawRate).coerceIn(-1.0, 1.0) * maxRollDeg
|
||||
rollAmount += desiredRoll - controller.roll
|
||||
controller.rotateRoll(rollAmount.toFloat())
|
||||
|
||||
//TODO: why does this affect the actual controller but rolling doesn't??
|
||||
// Do upwards movement based pitching
|
||||
// val maxVertSpeed = 0.25 //TODO: CONNECT UP TO JUMP
|
||||
// val currVertSpeed = state.rideVelocity.get().y
|
||||
// var desiredPitch = -(currVertSpeed / maxVertSpeed) * maxPitchDeg
|
||||
// pitchAmount += lerp(controller.pitch.toDouble(), desiredPitch, partialTicks.toDouble()) - controller.pitch
|
||||
// controller.rotatePitch(pitchAmount.toFloat())
|
||||
|
||||
}
|
||||
|
||||
private fun correctOrientation(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
controller: OrientationController,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
) {
|
||||
|
||||
// TODO: remove if not needed
|
||||
|
||||
// // Calculate correcting roll force.
|
||||
// // If the ride is moving then have the correction rate be an equal proportion of:
|
||||
// // - how rolled are you
|
||||
// // - how long has it been since last mouse input (higher is stronger correction)
|
||||
// // Also the correction is proportional as a whole to how NOT pitched are you so you don't spin endlessly when looking up or down
|
||||
// val howRolledAmI = sqrt(abs((cos(controller.roll.toRadians()) - 1.0f) * 0.5f)) // sqrt so it trends towards one pretty quickly
|
||||
// val maxRollCorrectionRate =
|
||||
// if (state.rideVelocity.get().length() < 0.2) 10.0f * abs(cos(controller.pitch.toRadians()))
|
||||
// else 10.0f * cos(controller.pitch.toRadians()).pow(2) * (
|
||||
// howRolledAmI*1.0f +
|
||||
// (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
// )
|
||||
// val maxRollForce = maxRollCorrectionRate / 40.0f
|
||||
// val rollArrivalDeg = 60.0f
|
||||
// val desiredRoll = 0.0f
|
||||
//
|
||||
// // Calculate the signed error (how far and in what direction)
|
||||
// val rollError = Mth.wrapDegrees(desiredRoll.angleDifference(controller.roll))
|
||||
//
|
||||
// // Use the absolute error to calculate the magnitude of the influence
|
||||
// val influenceMagnitude = (min(rollArrivalDeg, abs(rollError)) / rollArrivalDeg)
|
||||
// val desiredRollForce = maxRollCorrectionRate * influenceMagnitude * -rollError.sign
|
||||
// var steeredRollForce = desiredRollForce - state.currRollCorrectionForce.get()
|
||||
//
|
||||
// // Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
// if (abs(steeredRollForce) > maxRollForce) {
|
||||
// steeredRollForce = steeredRollForce.sign * maxRollForce
|
||||
// }
|
||||
//
|
||||
// // Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
// state.currRollCorrectionForce.set(
|
||||
// state.currRollCorrectionForce.get() + steeredRollForce
|
||||
// )
|
||||
|
||||
//Calculate correcting pitch force.
|
||||
// val rollCorrectionTimer = vehicle.runtime.resolveDouble(settings.timeToRollCorrect ?: globalSubmarine.timeToRollCorrect!!)
|
||||
// val maxPitchCorrectionRate = 5.0f * (state.noInputTime.get() - rollCorrectionTimer).coerceIn(0.0, 1.0).pow(2).toFloat()*0.5f
|
||||
// val maxPitchForce = maxPitchCorrectionRate / 40.0f
|
||||
// val pitchArrivalDeg = 45.0f
|
||||
// val desiredPitch = 0.0f
|
||||
//
|
||||
// if(state.rideVelocity.get().length() < 0.1 && state.noInputTime.get() > rollCorrectionTimer) {
|
||||
// val pitchErrror = Mth.wrapDegrees(desiredPitch.angleDifference(controller.pitch))
|
||||
// val arrivalInfluence = (min(pitchArrivalDeg,abs(pitchErrror)) / pitchArrivalDeg)
|
||||
// val desiredPitchForce = maxPitchCorrectionRate * arrivalInfluence * -pitchErrror.sign
|
||||
// var steeredPitchForce = desiredPitchForce - state.currPitchCorrectionForce.get()
|
||||
//
|
||||
// // Ensure the 'steering' correction force doesn't exceed our maxForce
|
||||
// if (abs(steeredPitchForce) > maxPitchForce) {
|
||||
// steeredPitchForce = steeredPitchForce.sign * maxPitchForce
|
||||
// }
|
||||
//
|
||||
// // Apply the 'steered' force (its really not a steering force I need a better name)
|
||||
// state.currPitchCorrectionForce.set(
|
||||
// state.currPitchCorrectionForce.get() + steeredPitchForce
|
||||
// )
|
||||
// } else {
|
||||
// state.currPitchCorrectionForce.set(
|
||||
// //reduce rollCorrection gradually
|
||||
// lerp(state.currPitchCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (vehicle !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (vehicle as OrientationControllable).orientationController
|
||||
|
||||
// Set roll to zero if transitioning to noroll config
|
||||
controller.rotateRoll(controller.roll * -1.0f)
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr ?: globalSubmarine.handlingExpr!!)
|
||||
val surfaceHandlingBoost = if(state.onSurface.get()) 3.0 else 1.0
|
||||
val effHandling = if(state.onSurface.get()) 1000 * deltaTime else handling * deltaTime
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = if(state.onSurface.get()) 10.0 else 2.0
|
||||
val mouseXc = (mouseX * 0.1).coerceIn(-effHandling, effHandling)
|
||||
val mouseYc = (mouseY * 0.1).coerceIn(-effHandling, effHandling)
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc, deltaTime * smoothingSpeed);
|
||||
|
||||
// Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput
|
||||
|
||||
// Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
controller.applyGlobalYaw(yawForce.toFloat())
|
||||
|
||||
var pitchRot = yInput
|
||||
// Pitch up globally
|
||||
val pitchLimit = 45.0
|
||||
if (abs(controller.pitch + pitchRot) >= pitchLimit ) {
|
||||
pitchRot = 0.0
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat())
|
||||
}
|
||||
|
||||
// If on the surface then conditionally bring the pitch to 0 degrees.
|
||||
if (state.onSurface.get()) {
|
||||
//move back at max 30 degrees per second.
|
||||
val maxCorrectionSpeed = 30.0
|
||||
val arrivalDegreeWidth = 30.0
|
||||
val currentPitch = controller.pitch
|
||||
val correctionDegrees = (-currentPitch / arrivalDegreeWidth).coerceIn(-1.0, 1.0) * maxCorrectionSpeed * deltaTime
|
||||
|
||||
controller.applyGlobalPitch(correctionDegrees.toFloat())
|
||||
|
||||
// Compensate player ride rotations
|
||||
// val playerRotater = driver as RideRotation
|
||||
// playerRotater.`cobblemon$setRideXRot`(playerRotater.`cobblemon$getRideXRot`() - correctionDegrees.toFloat() )
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Double {
|
||||
return if (!vehicle.isUnderWater) 1.0 else 0.1
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun mouseModifiesDriverRotation(settings: SubmarineSettings, state: SubmarineState, vehicle: PokemonEntity): Pair<Boolean, Boolean> {
|
||||
return Pair(false, state.onSurface.get())
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotateRiderHead(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getRideSounds(
|
||||
settings: SubmarineSettings,
|
||||
state: SubmarineState,
|
||||
vehicle: PokemonEntity
|
||||
): RideSoundSettingsList {
|
||||
return settings.rideSounds
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: SubmarineSettings) = SubmarineState()
|
||||
|
||||
}
|
||||
|
||||
class SubmarineSettings : RidingBehaviourSettings {
|
||||
override val key = SubmarineBehaviour.KEY
|
||||
override val stats = mutableMapOf<RidingStat, IntRange>()
|
||||
|
||||
var infiniteStamina: Expression? = null
|
||||
private set
|
||||
|
||||
var staminaRegenTime: Expression? = null
|
||||
private set
|
||||
|
||||
// Tope strafe speed in Bl/s
|
||||
var jumpExpr: Expression? = null
|
||||
// Yaw rate in degrees per second
|
||||
var handlingExpr: Expression? = null
|
||||
// Top speed in Bl/s
|
||||
var speedExpr: Expression? = null
|
||||
// Seconds to get to top speed
|
||||
var accelerationExpr: Expression? = null
|
||||
// Seconds of air provided by mount
|
||||
var staminaExpr: Expression? = null
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeRidingStats(stats)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeNullableExpression(infiniteStamina)
|
||||
buffer.writeNullableExpression(staminaRegenTime)
|
||||
buffer.writeNullableExpression(jumpExpr)
|
||||
buffer.writeNullableExpression(handlingExpr)
|
||||
buffer.writeNullableExpression(speedExpr)
|
||||
buffer.writeNullableExpression(accelerationExpr)
|
||||
buffer.writeNullableExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
stats.putAll(buffer.readRidingStats())
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
infiniteStamina = buffer.readNullableExpression()
|
||||
staminaRegenTime = buffer.readNullableExpression()
|
||||
jumpExpr = buffer.readNullableExpression()
|
||||
handlingExpr = buffer.readNullableExpression()
|
||||
speedExpr = buffer.readNullableExpression()
|
||||
accelerationExpr = buffer.readNullableExpression()
|
||||
staminaExpr = buffer.readNullableExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class SubmarineState : RidingBehaviourState() {
|
||||
var speed = ridingState(0.0, Side.CLIENT)
|
||||
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
var currPitchCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
var noInputTime = ridingState(0.0, Side.CLIENT)
|
||||
var onSurface = ridingState(false, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeBoolean(onSurface.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
onSurface.set(buffer.readBoolean(), forced = true)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
speed.set(0.0, forced = true)
|
||||
currRollCorrectionForce.set(0.0, forced = true)
|
||||
currPitchCorrectionForce.set(0.0, forced = true)
|
||||
noInputTime.set(0.0, forced = true)
|
||||
onSurface.set(false, forced = true)
|
||||
}
|
||||
|
||||
override fun copy() = SubmarineState().also {
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.speed.set(speed.get(), forced = true)
|
||||
it.rideVelocity.set(rideVelocity.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.onSurface.set(this.onSurface.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is SubmarineState) return false
|
||||
if (previous.onSurface.get() != onSurface.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -74,7 +74,7 @@ class RidingAnimationData(val ride: PokemonEntity)
|
||||
}
|
||||
if( r ) {
|
||||
//TODO: should this return?
|
||||
val controller = (ride as? OrientationControllable)?.orientationController ?: return
|
||||
val controller = (ride.firstPassenger as? OrientationControllable)?.orientationController ?: return
|
||||
val orientation = controller.orientation ?: Matrix3f()
|
||||
|
||||
val currPitch = controller.pitch
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
@@ -27,7 +25,6 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.Block
|
||||
@@ -43,9 +40,6 @@ import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.EntityCollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
@@ -96,13 +90,7 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!added) Containers.dropItemStack(
|
||||
level,
|
||||
source.pos.x.toDouble(),
|
||||
source.pos.y.toDouble(),
|
||||
source.pos.z.toDouble(),
|
||||
outputStack
|
||||
)
|
||||
if (!added) Containers.dropItemStack(level, source.pos.x.toDouble(), source.pos.y.toDouble(), source.pos.z.toDouble(), outputStack)
|
||||
}
|
||||
}
|
||||
stack
|
||||
@@ -120,27 +108,7 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
)
|
||||
}
|
||||
|
||||
override fun getCollisionShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape? {
|
||||
|
||||
if (context is EntityCollisionContext) {
|
||||
val entity = context.entity
|
||||
if (entity != null
|
||||
&& entity is MoLangScriptingEntity
|
||||
&& entity.config.map.getOrDefault("can_path_through_sacc_leaves", DoubleValue.ZERO).asDouble() == 1.0
|
||||
) {
|
||||
return Shapes.empty()
|
||||
}
|
||||
}
|
||||
return super.getCollisionShape(state, level, pos, context)
|
||||
}
|
||||
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean =
|
||||
true //!state.getValue(PERSISTENT) && state.getValue(DISTANCE) > 6
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean = !state.getValue(PERSISTENT) && state.getValue(DISTANCE) > 6
|
||||
|
||||
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val currentAge = state.getValue(AGE)
|
||||
@@ -155,8 +123,8 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
} else if (belowState.block is SaccharineLeafBlock) {
|
||||
val belowAge = belowState.getValue(AGE)
|
||||
if (belowAge < MAX_AGE) {
|
||||
world.setBlock(pos, changeAge(state, -1), UPDATE_CLIENTS)
|
||||
world.setBlock(belowPos, changeAge(belowState, 1), UPDATE_CLIENTS)
|
||||
changeAge(state, -1)
|
||||
changeAge(belowState, 1)
|
||||
}
|
||||
break
|
||||
} else {
|
||||
@@ -249,15 +217,7 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings) {
|
||||
|
||||
override fun isPathfindable(state: BlockState, type: PathComputationType): Boolean = false
|
||||
|
||||
override fun useItemOn(
|
||||
stack: ItemStack,
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hand: InteractionHand,
|
||||
hit: BlockHitResult
|
||||
): ItemInteractionResult {
|
||||
override fun useItemOn(stack: ItemStack, state: BlockState, level: Level, pos: BlockPos, player: Player, hand: InteractionHand, hit: BlockHitResult): ItemInteractionResult {
|
||||
if (!state.getValue(WATERLOGGED)) {
|
||||
val itemStack = player.getItemInHand(hand)
|
||||
val isGlassBottle = itemStack.`is`(Items.GLASS_BOTTLE)
|
||||
|
||||
@@ -69,11 +69,14 @@ import com.cobblemon.mod.common.client.tooltips.RecipeSeasoningAbsorbtionTooltip
|
||||
import com.cobblemon.mod.common.client.tooltips.SeasoningTooltipGenerator
|
||||
import com.cobblemon.mod.common.client.tooltips.TooltipManager
|
||||
import com.cobblemon.mod.common.client.trade.ClientTrade
|
||||
import com.cobblemon.mod.common.debug.RidingDebugRenderer
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.isLookingAt
|
||||
import io.github.flemmli97.debugutils.api.RegisterDebugRenderers
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.color.block.BlockColor
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
@@ -193,6 +196,11 @@ object CobblemonClient {
|
||||
}
|
||||
ClientPlayerIcon.onTick()
|
||||
}
|
||||
|
||||
val debugId = cobblemonResource("riding")
|
||||
RegisterDebugRenderers.registerCustomDebugRenderer(debugId, RidingDebugRenderer)
|
||||
RegisterDebugRenderers.registerServerToggle(debugId)
|
||||
RegisterDebugRenderers.registerClientHandler(debugId) { RidingDebugRenderer.clientHandler(it) }
|
||||
}
|
||||
|
||||
private fun registerTooltipManagers() {
|
||||
|
||||
-1
@@ -45,7 +45,6 @@ class CobblemonConfigScreen(
|
||||
|
||||
val clonedConfig = Cobblemon.config.clone()
|
||||
val defaultConfig = CobblemonConfig()
|
||||
val hideServerConfigs = Minecraft.getInstance().currentServer != null && !Minecraft.getInstance().isLocalServer
|
||||
|
||||
private lateinit var layout: HeaderAndFooterLayout
|
||||
private lateinit var searchEdit: EditBox
|
||||
|
||||
-7
@@ -21,7 +21,6 @@ import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.config.Category
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.SERVER
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import net.minecraft.SharedConstants
|
||||
import net.minecraft.client.Minecraft
|
||||
@@ -33,7 +32,6 @@ import net.minecraft.client.gui.narration.NarratableEntry
|
||||
import kotlin.math.min
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
@@ -64,11 +62,6 @@ class CobblemonConfigVariableList(
|
||||
return@map null
|
||||
}
|
||||
|
||||
val fieldAnnotation = property.javaField!!.getAnnotation(CobblemonConfigField::class.java)
|
||||
if (parent.hideServerConfigs && fieldAnnotation.side == SERVER) {
|
||||
return@map null
|
||||
}
|
||||
|
||||
val entry: CobblemonConfigVariable? =
|
||||
when (val classifier = property.returnType.classifier) {
|
||||
String::class -> CobblemonConfigStringVariable(this, property as KMutableProperty1<out CobblemonConfig, String>)
|
||||
|
||||
+4
-26
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.client.gui.debug.riding
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
@@ -90,7 +89,7 @@ class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity
|
||||
for (variable in expressionVariables) {
|
||||
val (name, value) = variable
|
||||
|
||||
val editBox = EditBox(this.minecraft!!.font, 130, currentY, 300, 20, name.text())
|
||||
val editBox = EditBox(this.minecraft!!.font, 110, currentY, 300, 20, name.text())
|
||||
editBox.setMaxLength(256)
|
||||
editBox.value = value
|
||||
|
||||
@@ -159,10 +158,6 @@ class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity
|
||||
val clazz = settings.javaClass
|
||||
val fields = clazz.declaredFields
|
||||
|
||||
val gsField = CobblemonRideSettings.javaClass.declaredFields.firstOrNull { it.type == clazz }
|
||||
gsField?.isAccessible = true
|
||||
val controllerGlobalSettings = gsField?.get(CobblemonRideSettings) as? RidingBehaviourSettings?
|
||||
|
||||
// Iterate through all expression fields and return the list of those that
|
||||
// aer expressions
|
||||
return fields.mapNotNull { field ->
|
||||
@@ -170,18 +165,10 @@ class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity
|
||||
field.isAccessible = true // Make private fields accessible
|
||||
val name = field.name
|
||||
// Get the value, cast it, and call .getString() on it
|
||||
if (field.get(settings) != null) {
|
||||
val value = (field.get(settings) as Expression).getString()
|
||||
val value = (field.get(settings) as Expression).getString()
|
||||
|
||||
// Create the pair and return it for the list
|
||||
name to value
|
||||
|
||||
} else {
|
||||
// If the settings field is null then check for a global setting
|
||||
val value = getMatchingGlobalSettingsValue(settings, controllerGlobalSettings, name) ?: "novalue"
|
||||
|
||||
name to value
|
||||
}
|
||||
// Create the pair and return it for the list
|
||||
name to value
|
||||
} else {
|
||||
// If it's not an Expression (they all honestly should be if being used by the
|
||||
// behaviour in question) then ignore
|
||||
@@ -189,13 +176,4 @@ class RideSettingsEditorGUI(val parentScreen: Screen, val vehicle: PokemonEntity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMatchingGlobalSettingsValue(settings: RidingBehaviourSettings, globalSettings: RidingBehaviourSettings?, fieldName: String): String? {
|
||||
if (globalSettings == null) return null
|
||||
val gssField = globalSettings.javaClass.declaredFields.firstOrNull {
|
||||
it.name == fieldName
|
||||
}
|
||||
gssField?.isAccessible = true
|
||||
return (gssField?.get(globalSettings) as? Expression)?.getString()
|
||||
}
|
||||
}
|
||||
+21
-27
@@ -25,8 +25,6 @@ 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.EVs
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
@@ -76,7 +74,6 @@ class StatWidget(
|
||||
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 statsChartPentagonHighlightResource = cobblemonResource("textures/gui/summary/summary_stats_chart_pentagon_highlight.png")
|
||||
private val statsOtherBaseResource = cobblemonResource("textures/gui/summary/summary_stats_other_base.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")
|
||||
@@ -293,34 +290,33 @@ class StatWidget(
|
||||
}
|
||||
} else {
|
||||
if (renderPentagonStats) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = statsChartPentagonResource,
|
||||
x= (x + 20.5) / SCALE,
|
||||
y = (y + 22) / SCALE,
|
||||
width = 186,
|
||||
height = 176,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
pokemon.form.riding.behaviours?.let {
|
||||
val behaviours = it.entries.toList()
|
||||
val selectedBehaviour = behaviours[rideBehaviourIndex]
|
||||
val canSwitchStyle = behaviours.size > 1 && centerHovered(pMouseX, pMouseY)
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = if (canSwitchStyle) statsChartPentagonHighlightResource else statsChartPentagonResource,
|
||||
x= (x + 20.5) / SCALE,
|
||||
y = (y + 22) / SCALE,
|
||||
width = 186,
|
||||
height = 176,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
val pentagonColour = when (selectedBehaviour.key) {
|
||||
RidingStyle.AIR -> {
|
||||
if (canSwitchStyle)
|
||||
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 (canSwitchStyle)
|
||||
if (behaviours.size > 1 && centerHovered(pMouseX, pMouseY))
|
||||
Vector3f(95F/255F, 165F/255F, 1F)
|
||||
else Vector3f(65F/255F, 135F/255F, 1F)
|
||||
}
|
||||
else -> {
|
||||
if (canSwitchStyle)
|
||||
if (behaviours.size > 1 && centerHovered(pMouseX, pMouseY))
|
||||
Vector3f(1F, 195F/255F, 30F/255F)
|
||||
else Vector3f(1F, 165F/255F, 0F)
|
||||
}
|
||||
@@ -357,8 +353,8 @@ class StatWidget(
|
||||
context = context,
|
||||
labels = RidingStat.entries.toList().map { stat ->
|
||||
if (statLabelsHovered(pentagonVerticesOffset, pMouseX, pMouseY))
|
||||
"+${floor(pokemon.getRideBoost(stat) / pokemon.getMaxRideBoost(stat) * 100)}%".text()
|
||||
else floor(pokemon.getRideStat(selectedBehaviour.key, stat)).toString().text()
|
||||
"${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
|
||||
@@ -393,7 +389,7 @@ class StatWidget(
|
||||
colour = Vector3f(216F/255, 100F/255, 1F)
|
||||
)
|
||||
EV -> drawStatPolygon(
|
||||
statLabels.values.map { (pokemon.evs[it]?.toFloat() ?: 0F) / EVs.MAX_STAT_VALUE.toFloat() },
|
||||
statLabels.values.map { (pokemon.evs[it]?.toFloat() ?: 0F) / 252F },
|
||||
colour = Vector3f(1F, 1F, 100F/255F)
|
||||
)
|
||||
}
|
||||
@@ -407,9 +403,9 @@ class StatWidget(
|
||||
"${
|
||||
if (pokemon.ivs.isHyperTrained(stat.value)) "${pokemon.ivs[stat.value]} (${pokemon.ivs.hyperTrainedIVs[stat.value]})"
|
||||
else pokemon.ivs[stat.value].toString()
|
||||
}/${IVs.MAX_VALUE}".text()
|
||||
}/31".text()
|
||||
}
|
||||
EV -> "${pokemon.evs.getOrDefault(stat.value)}/${EVs.MAX_STAT_VALUE}".text()
|
||||
EV -> "${pokemon.evs.getOrDefault(stat.value)}/252".text()
|
||||
else -> stat.key
|
||||
}
|
||||
} else { stat.key }
|
||||
@@ -494,14 +490,14 @@ class StatWidget(
|
||||
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) / IVs.MAX_VALUE.toDouble()) * 100)}%"
|
||||
"${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) / EVs.MAX_STAT_VALUE.toDouble()) * 100)}%"
|
||||
(if (asPercent) "${floor((pokemon.evs.getOrDefault(stat) / 252.0) * 100)}%"
|
||||
else pokemon.evs.getOrDefault(stat).toString()).text()
|
||||
}
|
||||
else -> "0".text()
|
||||
@@ -562,9 +558,7 @@ class StatWidget(
|
||||
}
|
||||
|
||||
private fun centerHovered(pMouseX: Number, pMouseY: Number): Boolean {
|
||||
val centerX = x + (WIDTH / 2)
|
||||
val centerY = y + (HEIGHT / 2)
|
||||
return (pMouseX.toInt() in (centerX - 30)..(centerX + 30)) && (pMouseY.toInt() in (centerY - 30)..(centerY + 30))
|
||||
return (pMouseX.toInt() in (x + 44)..(x + 90)) && (pMouseY.toInt() in (y + 47)..(y + 93))
|
||||
}
|
||||
|
||||
private fun statLabelsHovered(labelOffsets: List<Pair<Double, Double>>, mouseX: Int, mouseY: Int): Boolean {
|
||||
|
||||
+5
-5
@@ -9,12 +9,13 @@
|
||||
package com.cobblemon.mod.common.client.net.data
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRideSettings
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.data.RideSettingsSyncPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object RideSettingsSyncHandler : ClientNetworkPacketHandler<RideSettingsSyncPacket> {
|
||||
override fun handle(packet: RideSettingsSyncPacket, client: Minecraft) {
|
||||
object RideSettingsSyncHandler : ServerNetworkPacketHandler<RideSettingsSyncPacket> {
|
||||
override fun handle(packet: RideSettingsSyncPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
CobblemonRideSettings.bird = packet.bird
|
||||
CobblemonRideSettings.glider = packet.glider
|
||||
CobblemonRideSettings.helicopter = packet.helicopter
|
||||
@@ -29,6 +30,5 @@ object RideSettingsSyncHandler : ClientNetworkPacketHandler<RideSettingsSyncPack
|
||||
CobblemonRideSettings.boat = packet.boat
|
||||
CobblemonRideSettings.burst = packet.burst
|
||||
CobblemonRideSettings.dolphin = packet.dolphin
|
||||
CobblemonRideSettings.submarine = packet.submarine
|
||||
}
|
||||
}
|
||||
+7
-26
@@ -10,41 +10,22 @@ package com.cobblemon.mod.common.client.net.orientation
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.duck.RidePassenger
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.util.Mth
|
||||
|
||||
object S2CUpdateOrientationHandler : ClientNetworkPacketHandler<ClientboundUpdateOrientationPacket> {
|
||||
override fun handle(packet: ClientboundUpdateOrientationPacket, client: Minecraft) {
|
||||
client.executeIfPossible {
|
||||
val level = client.level ?: return@executeIfPossible
|
||||
val player = client.player ?: return@executeIfPossible
|
||||
val vehicle = level.getEntity(packet.entityId)
|
||||
val vehicleController = if (vehicle is OrientationControllable) vehicle.orientationController else return@executeIfPossible
|
||||
|
||||
// If the client is also the driver of this entity then don't update it as the driver is the source
|
||||
// of truth on vehicle orientation updates.
|
||||
if (vehicle.controllingPassenger != player) {
|
||||
packet.active?.let { shouldUseCustomOrientation ->
|
||||
|
||||
val playerIsPassenger = vehicle.passengers.contains(player)
|
||||
|
||||
// If the player has just switched to riding a custom orientation ride then set their
|
||||
// ride x and y rots local to the vehicle rots(if the controller wasn't active and will now be active)
|
||||
// This ensures that on transition your camera stays in the same spot
|
||||
if (!vehicleController.isActive() && shouldUseCustomOrientation && playerIsPassenger) {
|
||||
// Set local to the vehicle x and yrot
|
||||
val playerRotater = player as RidePassenger?
|
||||
if (playerRotater != null) {
|
||||
playerRotater.`cobblemon$setRideXRot`(Mth.wrapDegrees(player.getXRot() - vehicle.getXRot()))
|
||||
playerRotater.`cobblemon$setRideYRot`(Mth.wrapDegrees(player.getYRot() - vehicle.getYRot()))
|
||||
}
|
||||
val entity = level.getEntity(packet.entityId)
|
||||
if (entity is OrientationControllable) {
|
||||
packet.active?.let {
|
||||
entity.orientationController.active = it
|
||||
if (!it) {
|
||||
entity.orientationController.reset()
|
||||
}
|
||||
|
||||
vehicle.orientationController.active = shouldUseCustomOrientation
|
||||
}
|
||||
vehicle.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
entity.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+80
-70
@@ -15,23 +15,23 @@ import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository.getPoser
|
||||
import com.cobblemon.mod.common.duck.RidePassenger
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.mixin.accessor.CameraAccessor
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.Camera
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.level.ClipContext
|
||||
import net.minecraft.world.phys.HitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Vector3f
|
||||
|
||||
object MountedCameraRenderer
|
||||
{
|
||||
fun getCameraPosition(
|
||||
instance: Camera,
|
||||
driver: Entity,
|
||||
entity: Entity,
|
||||
vehicle: Entity,
|
||||
x: Double,
|
||||
y: Double,
|
||||
@@ -51,86 +51,99 @@ object MountedCameraRenderer
|
||||
Mth.lerp(instance.partialTickTime.toDouble(), vehicle.zOld, vehicle.z)
|
||||
)
|
||||
setup(vehicle, instance.partialTickTime)
|
||||
val rollable = vehicle as OrientationControllable
|
||||
val vehicleController = rollable.getOrientationController()
|
||||
val rollable = entity as OrientationControllable
|
||||
val controller = rollable.getOrientationController()
|
||||
|
||||
val model = getPoser(vehicle.pokemon.species.resourceIdentifier, FloatingState())
|
||||
|
||||
val locatorName = delegate.getSeatLocator(driver)
|
||||
val locator = delegate.locatorStates[locatorName] ?: return null
|
||||
|
||||
val currEyeHeight: Double = Mth.lerp(instance.partialTickTime.toDouble(), eyeHeight, eyeHeightOld)
|
||||
var offset = Vector3f(0f, (currEyeHeight - (driver.bbHeight / 2)).toFloat(), 0f)
|
||||
var eyeOffset = Vector3f(0f, (currEyeHeight - (driver.bbHeight / 2)).toFloat(), 0f)
|
||||
// First person and view bobbing are handled the same way.
|
||||
if (!instance.isDetached || Cobblemon.config.thirdPersonViewBobbing) {
|
||||
val delegate = vehicle.delegate as PokemonClientDelegate
|
||||
val locatorName = delegate.getSeatLocator(entity)
|
||||
val locator = delegate.locatorStates[locatorName]
|
||||
|
||||
// Get additional offset from poser and add to the eyeHeight offset
|
||||
val shouldFlip = !(vehicleController.active && vehicleController.orientation != null) // Do not flip the offset for 3rd person reverse unless we are using normal mc camera rotation.
|
||||
|
||||
eyeOffset.add(getFirstPersonOffset(model, locatorName))
|
||||
if (!instance.isDetached) {
|
||||
offset.add(
|
||||
getFirstPersonOffset(model, locatorName)
|
||||
)
|
||||
} else if( Cobblemon.config.thirdPersonViewBobbing) {
|
||||
offset.add(
|
||||
getThirdPersonOffset(thirdPersonReverse, model.thirdPersonCameraOffset, locatorName, shouldFlip)
|
||||
)
|
||||
} else {
|
||||
offset.add(
|
||||
getThirdPersonOffset(thirdPersonReverse, model.thirdPersonCameraOffsetNoViewBobbing, locatorName, shouldFlip)
|
||||
)
|
||||
}
|
||||
|
||||
// Grab the current camera rotation to use as the offset rotation.
|
||||
val offsetRot = instance.rotation()
|
||||
offset = offsetRot.transform(offset)
|
||||
eyeOffset = offsetRot.transform(eyeOffset)
|
||||
|
||||
val eyeLocatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
|
||||
val eyePos = eyeLocatorOffset.add(entityPos).toVector3f()
|
||||
|
||||
// Get the camera position. If 3rd person viewbobbing is enabled or the player is
|
||||
// in first person then base the camera position off the seat locator offset
|
||||
val pos = if (!instance.isDetached || Cobblemon.config.thirdPersonViewBobbing) {
|
||||
val locatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
|
||||
locatorOffset.add(entityPos).toVector3f()
|
||||
} else {
|
||||
val pokemonCenter = Vector3f(0f, driver.bbHeight/2, 0f)
|
||||
entityPos.toVector3f().add(pokemonCenter)
|
||||
if (locator == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val offsetDistance = offset.length()
|
||||
val offsetDirection = offset.mul(1 / offsetDistance)
|
||||
val locatorOffset = Vec3(locator.matrix.getTranslation(Vector3f()))
|
||||
|
||||
val eyeOffsetDistance = eyeOffset.length()
|
||||
val eyeOffsetDirection = eyeOffset.mul(1 / eyeOffsetDistance)
|
||||
// Get Eye height
|
||||
val currEyeHeight: Double = Mth.lerp(instance.partialTickTime.toDouble(), eyeHeight, eyeHeightOld)
|
||||
var offset = Vector3f(0f, (currEyeHeight - (entity.bbHeight / 2)).toFloat(), 0f)
|
||||
|
||||
// Use getMaxZoom to calculate clipping
|
||||
val maxZoom: Float = getMaxZoom(offsetDistance, offsetDirection, pos, instance)
|
||||
val eyeMaxZoom: Float = getMaxZoom(eyeOffsetDistance, eyeOffsetDirection, eyePos, instance)
|
||||
// Get additional offset from poser and add to the eyeHeight offset
|
||||
if (!instance.isDetached) {
|
||||
offset.add(
|
||||
getFirstPersonOffset(model, locatorName)
|
||||
)
|
||||
} else {
|
||||
offset.add(
|
||||
getThirdPersonOffset(thirdPersonReverse, model.thirdPersonCameraOffset, locatorName)
|
||||
)
|
||||
}
|
||||
|
||||
val playerRotater = driver as RidePassenger
|
||||
playerRotater.`cobblemon$setRideEyePos`(Vec3(eyeOffsetDirection.mul(eyeMaxZoom).add(eyePos)).add(0.0, 2.0, 0.0))
|
||||
return Vec3(offsetDirection.mul(maxZoom).add(pos))
|
||||
}
|
||||
if (controller.isActive()) {
|
||||
offset = controller.getRenderOrientation(instance.partialTickTime).transform(offset)
|
||||
} else {
|
||||
offset = Axis.YP.rotationDegrees(180f - instance.yRot).transform(offset)
|
||||
}
|
||||
|
||||
fun resetDriverRotations(
|
||||
instance: Camera,
|
||||
driver: Entity,
|
||||
) {
|
||||
val eulerAngs = Quaternionf(instance.rotation()).getEulerAnglesYXZ(Vector3f())
|
||||
val playerRotater = driver as RidePassenger
|
||||
// Backticks because kotlin explodes otherwise due to syntax
|
||||
playerRotater.`cobblemon$setRideXRot`(-eulerAngs.x() * Mth.RAD_TO_DEG)
|
||||
playerRotater.`cobblemon$setRideYRot`(180.0f - (eulerAngs.y() * Mth.RAD_TO_DEG))
|
||||
val pos = locatorOffset.add(entityPos).toVector3f()
|
||||
val offsetDistance = offset.length()
|
||||
val offsetDirection = offset.mul(1 / offsetDistance)
|
||||
|
||||
// Use getMaxZoom to calculate clipping
|
||||
val maxZoom: Float = getMaxZoom(offsetDistance, offsetDirection, pos, instance)
|
||||
|
||||
return Vec3(offsetDirection.mul(maxZoom).add(pos))
|
||||
} else {
|
||||
val xRot = (-1 * Math.toRadians(instance.xRot.toDouble())).toFloat()
|
||||
|
||||
// get orientation based on OrientationController or normal rotations
|
||||
val orientation =
|
||||
if (controller.isActive() && controller.orientation != null)
|
||||
controller.orientation!!
|
||||
else
|
||||
Matrix3f()
|
||||
.rotateY(Math.toRadians((180f - instance.yRot).toDouble()).toFloat())
|
||||
.rotateX(xRot)
|
||||
|
||||
// Get pivot from poser
|
||||
val pivotOffsets = model.thirdPersonPivotOffset
|
||||
val pokemonCenter = Vector3f(0f, entity.bbHeight/2, 0f)
|
||||
|
||||
var pivot = Vector3f(pokemonCenter)
|
||||
val locatorName = delegate.getSeatLocator(entity)
|
||||
if (pivotOffsets.containsKey(locatorName)) {
|
||||
pivot = pivotOffsets[locatorName]!!.toVector3f()
|
||||
pivot.sub(pokemonCenter)
|
||||
orientation.transform(pivot)
|
||||
pivot.add(pokemonCenter)
|
||||
}
|
||||
|
||||
val pos = entityPos.toVector3f().add(pivot)
|
||||
|
||||
// Get offset from poser
|
||||
val offset = getThirdPersonOffset(thirdPersonReverse, model.thirdPersonCameraOffsetNoViewBobbing, locatorName)
|
||||
|
||||
val rotatedOffset = orientation.transform(offset)
|
||||
val offsetDistance = rotatedOffset.length()
|
||||
val offsetDirection = rotatedOffset.mul(1 / offsetDistance)
|
||||
|
||||
// Use getMaxZoom to calculate clipping
|
||||
val maxZoom: Float = getMaxZoom(offsetDistance, offsetDirection, pos, instance)
|
||||
|
||||
return Vec3(offsetDirection.mul(maxZoom).add(pos))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun getThirdPersonOffset(
|
||||
thirdPersonReverse: Boolean,
|
||||
cameraOffsets: Map<String, Vec3>,
|
||||
locatorName: String,
|
||||
shouldFlip: Boolean = true
|
||||
locatorName: String
|
||||
): Vector3f {
|
||||
val offset = if (thirdPersonReverse && cameraOffsets.containsKey(locatorName + "_reverse")) {
|
||||
cameraOffsets[locatorName + "_reverse"]!!.toVector3f()
|
||||
@@ -139,10 +152,7 @@ object MountedCameraRenderer
|
||||
} else {
|
||||
Vector3f(0f, 2f, 4f)
|
||||
}
|
||||
|
||||
// Don't need to account for this since orientation is derived from camera rotation and that z is already flipped.
|
||||
// Flip only when not on a rollable.
|
||||
if (thirdPersonReverse && shouldFlip) offset.z *= -1
|
||||
if (thirdPersonReverse) offset.z *= -1
|
||||
return offset
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -747,8 +747,9 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
// If scale is 0 we start getting NaNs
|
||||
scale.coerceAtLeast(0.01f)
|
||||
if (entity.passengers.isNotEmpty() && entity.controllingPassenger is OrientationControllable
|
||||
&& (entity as OrientationControllable).orientationController.active){
|
||||
val controller = entity.orientationController
|
||||
&& (entity.controllingPassenger as OrientationControllable).orientationController.active){
|
||||
val controllingPassenger = entity.controllingPassenger as OrientationControllable
|
||||
val controller = controllingPassenger.orientationController
|
||||
val transformationMatrix = Matrix4f()
|
||||
val center = Vector3f(0f, entity.bbHeight/2, 0f)
|
||||
transformationMatrix.translate(center)
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class BeheeyemModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("beheeyem")
|
||||
override val head = getPart("head")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
|
||||
override var portraitScale = 3.0F
|
||||
override var portraitTranslation = Vec3(-0.34, -0.8, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("beheeyem", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("beheeyem", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("beheeyem", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 5,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("beheeyem", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ChandelureModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("chandelure")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 1.85F
|
||||
override var portraitTranslation = Vec3(-0.3, -0.19, 0.0)
|
||||
|
||||
override var profileScale = 0.81F
|
||||
override var profileTranslation = Vec3(0.0, 0.68, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var hover: CobblemonPose
|
||||
lateinit var flying: CobblemonPose
|
||||
lateinit var battle_idle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("chandelure", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("chandelure", "blink") }
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES - PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES - PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
hover = registerPose(
|
||||
poseName = "hover",
|
||||
poseType = PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
flying = registerPose(
|
||||
poseName = "flying",
|
||||
poseType = PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "air_fly")
|
||||
)
|
||||
)
|
||||
|
||||
battle_idle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("chandelure", "battle_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("chandelure", "faint") else null
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ElgyemModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("elgyem")
|
||||
override val head = getPart("head")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
|
||||
override var portraitScale = 2.5F
|
||||
override var portraitTranslation = Vec3(-0.2, -0.8, 0.0)
|
||||
|
||||
override var profileScale = 0.85F
|
||||
override var profileTranslation = Vec3(0.0, 0.5, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var battleidle: Pose
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("elgyem", "cry") }
|
||||
|
||||
val shoulderOffset = 5.6
|
||||
|
||||
override fun registerPoses() {
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("elgyem", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
condition = { !it.isBattling },
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 5,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
transformTicks = 10,
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "battle_idle")
|
||||
)
|
||||
)
|
||||
|
||||
shoulderLeft = registerPose(
|
||||
poseType = PoseType.SHOULDER_LEFT,
|
||||
//quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, shoulderOffset)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderRight = registerPose(
|
||||
poseType = PoseType.SHOULDER_RIGHT,
|
||||
//quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("elgyem", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(ModelPartTransformation.X_AXIS, -shoulderOffset)
|
||||
)
|
||||
)
|
||||
}
|
||||
override fun getFaintAnimation(state: PosableState) = if (state.isPosedIn(standing, walk, battleidle, sleep)) bedrockStateful("elgyem", "faint") else null
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class LampentModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("lampent")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.19, -0.17, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var hover: CobblemonPose
|
||||
lateinit var flying: CobblemonPose
|
||||
lateinit var battle_idle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("lampent", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("lampent", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "sleep")
|
||||
)
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES - PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES - PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
hover = registerPose(
|
||||
poseName = "hover",
|
||||
poseType = PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
flying = registerPose(
|
||||
poseName = "flying",
|
||||
poseType = PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "air_fly")
|
||||
)
|
||||
)
|
||||
|
||||
battle_idle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("lampent", "battle_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("lampent", "faint") else null
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class LitwickModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("litwick")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.33F
|
||||
override var portraitTranslation = Vec3(0.01, -1.9, 0.0)
|
||||
|
||||
override var profileScale = 0.86F
|
||||
override var profileTranslation = Vec3(0.0, 0.44, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
lateinit var battle_idle: CobblemonPose
|
||||
lateinit var shoulderLeft: CobblemonPose
|
||||
lateinit var shoulderRight: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("litwick", "cry") }
|
||||
|
||||
val shoulderOffset = 5.5
|
||||
val wax = getPart("wax_trail")
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("litwick", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "sleep")
|
||||
)
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
condition = { !it.isBattling },
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battle_idle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "battle_idle")
|
||||
)
|
||||
)
|
||||
|
||||
shoulderLeft = registerPose(
|
||||
poseType = PoseType.SHOULDER_LEFT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
wax.createTransformation().withVisibility(visibility = false)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderRight = registerPose(
|
||||
poseType = PoseType.SHOULDER_RIGHT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("litwick", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
wax.createTransformation().withVisibility(visibility = false)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("litwick", "faint") else null
|
||||
}
|
||||
+5
@@ -361,6 +361,8 @@ object VaryingModelRepository {
|
||||
inbuilt("chespin", :: ChespinModel)
|
||||
inbuilt("quilladin", :: QuilladinModel)
|
||||
inbuilt("chesnaught", :: ChesnaughtModel)
|
||||
inbuilt("elgyem", :: ElgyemModel)
|
||||
inbuilt("beheeyem", :: BeheeyemModel)
|
||||
inbuilt("pineco", :: PinecoModel)
|
||||
inbuilt("forretress", :: ForretressModel)
|
||||
inbuilt("lotad", :: LotadModel)
|
||||
@@ -552,6 +554,9 @@ object VaryingModelRepository {
|
||||
inbuilt("gurdurr", ::GurdurrModel)
|
||||
inbuilt("conkeldurr", ::ConkeldurrModel)
|
||||
inbuilt("clodsire", ::ClodsireModel)
|
||||
inbuilt("litwick", ::LitwickModel)
|
||||
inbuilt("lampent", ::LampentModel)
|
||||
inbuilt("chandelure", ::ChandelureModel)
|
||||
inbuilt("gimmighoulchest", ::GimmighoulChestModel)
|
||||
inbuilt("drifloon", ::DrifloonModel)
|
||||
inbuilt("lileep", ::LileepModel)
|
||||
|
||||
+13
-7
@@ -42,9 +42,14 @@ import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.math.DoubleRange
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.math.remap
|
||||
import com.google.common.primitives.Floats
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.math.Axis
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.Font.DisplayMode
|
||||
@@ -62,8 +67,11 @@ import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.*
|
||||
import kotlin.math.*
|
||||
import org.joml.Math
|
||||
import org.joml.Matrix4f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import org.joml.Vector4f
|
||||
|
||||
class PokemonRenderer(
|
||||
context: EntityRendererProvider.Context
|
||||
@@ -181,14 +189,12 @@ class PokemonRenderer(
|
||||
buffer: MultiBufferSource,
|
||||
packedLight: Int
|
||||
) {
|
||||
val rollable = entity as? OrientationControllable ?: return
|
||||
val driver = entity.firstPassenger ?: return
|
||||
val rollable = driver as? OrientationControllable ?: return
|
||||
val controller = rollable.orientationController
|
||||
poseMatrix.pushPose()
|
||||
|
||||
if (!DISABLE_ROLLING_DEBUG && controller.active) {
|
||||
// Allow the ride controller to modify its rotations using partialTick
|
||||
entity.applyRenderRotation(partialTicks)
|
||||
|
||||
val matrix = poseMatrix.last().pose()
|
||||
val yaw = Mth.rotLerp(partialTicks, entity.yBodyRotO, entity.yBodyRot)
|
||||
val center = Vector3f(0f, entity.bbHeight/2, 0f)
|
||||
|
||||
+3
@@ -23,6 +23,9 @@ object CobblemonTooltipGenerator : TooltipGenerator() {
|
||||
val resultLines = mutableListOf<Component>()
|
||||
|
||||
if (stack.item.builtInRegistryHolder().unwrapKey().isPresent && stack.item.builtInRegistryHolder().unwrapKey().get().location().namespace == Cobblemon.MODID) {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
val language = Language.getInstance()
|
||||
val key = this.baseLangKeyForItem(stack)
|
||||
if (language.has(key)) {
|
||||
|
||||
+6
@@ -31,6 +31,9 @@ object FishingBaitTooltipGenerator : TooltipGenerator() {
|
||||
private val fishingBaitItemClass by lazy { lang("item_class.fishing_bait").blue() }
|
||||
|
||||
override fun generateCategoryTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
if (!SpawnBaitEffects.isFishingBait(stack)) {
|
||||
return null
|
||||
}
|
||||
@@ -38,6 +41,9 @@ object FishingBaitTooltipGenerator : TooltipGenerator() {
|
||||
}
|
||||
|
||||
override fun generateAdditionalTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
val resultLines = mutableListOf<Component>()
|
||||
|
||||
if (SpawnBaitEffects.isFishingBait(stack)) resultLines.add(this.fishingBaitItemClass)
|
||||
|
||||
+3
@@ -23,6 +23,9 @@ import net.minecraft.world.item.ItemStack
|
||||
|
||||
object FishingRodTooltipGenerator : TooltipGenerator() {
|
||||
override fun generateTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
val resultLines = mutableListOf<Component>()
|
||||
|
||||
val rod = (stack.item as? PokerodItem)?.pokeRodId?.let { PokeRods.getPokeRod(it) } ?: return null
|
||||
|
||||
+4
@@ -61,6 +61,10 @@ object SeasoningTooltipGenerator : TooltipGenerator() {
|
||||
}
|
||||
|
||||
override fun generateAdditionalTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val isSeasoningIngredient = Seasonings.isSeasoning(stack)
|
||||
val flavors = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours
|
||||
val food = stack.get(CobblemonItemComponents.FOOD)
|
||||
|
||||
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.client.tooltips
|
||||
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.core.component.DataComponents
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
@@ -23,12 +22,6 @@ object TooltipManager {
|
||||
}
|
||||
|
||||
fun generateTooltips(stack: ItemStack, lines: MutableList<Component>, hasShiftDown: Boolean) {
|
||||
// This will need to be changed in 1.21.5 as 25w04a changed the following:
|
||||
// "Removed the hide_tooltip and hide_additional_tooltip components in favor of the new tooltip_display component."
|
||||
if (stack.get(DataComponents.HIDE_ADDITIONAL_TOOLTIP) != null) {
|
||||
return
|
||||
}
|
||||
|
||||
val standardLines = tooltipGenerators.flatMap {
|
||||
val innerLines = mutableListOf<Component>()
|
||||
val regularTooltip = it.generateTooltip(stack, lines)
|
||||
|
||||
@@ -12,8 +12,6 @@ import com.cobblemon.mod.common.api.drop.ItemDropMethod
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.client.gui.portrait.PortraitStyle
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.CLIENT
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.SERVER
|
||||
import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.pokeball.catching.calculators.CobblemonCaptureCalculator
|
||||
import com.cobblemon.mod.common.util.adapters.CaptureCalculatorAdapter
|
||||
@@ -21,9 +19,9 @@ import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class CobblemonConfig {
|
||||
companion object {
|
||||
@@ -39,123 +37,123 @@ class CobblemonConfig {
|
||||
|
||||
var lastSavedVersion: String = "0.0.1"
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_pokemon_level", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_pokemon_level")
|
||||
@IntConstraint(min = 1, max = 1000)
|
||||
var maxPokemonLevel = 100
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_pokemon_friendship", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_pokemon_friendship")
|
||||
@IntConstraint(min = 0, max = 1000)
|
||||
var maxPokemonFriendship = 255
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "announce_drop_items", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "announce_drop_items")
|
||||
var announceDropItems = true
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "default_drop_item_method", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "default_drop_item_method")
|
||||
var defaultDropItemMethod = ItemDropMethod.ON_ENTITY
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "drops_after_death_animation", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "drops_after_death_animation")
|
||||
var dropAfterDeathAnimation = false
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "ambient_pokemon_cry_ticks", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "ambient_pokemon_cry_ticks")
|
||||
@LastChangedVersion("1.4.0")
|
||||
var ambientPokemonCryTicks = 1080
|
||||
|
||||
@CobblemonConfigField(Category.Storage, lang = "default_box_count", SERVER)
|
||||
@CobblemonConfigField(Category.Storage, lang = "default_box_count")
|
||||
@IntConstraint(min = 1, max = 1000)
|
||||
@LastChangedVersion("1.7.0")
|
||||
var defaultBoxCount = 40
|
||||
@CobblemonConfigField(Category.Storage, lang = "pokemon_save_interval_seconds", SERVER)
|
||||
@CobblemonConfigField(Category.Storage, lang = "pokemon_save_interval_seconds")
|
||||
@IntConstraint(min = 1, max = 120)
|
||||
var pokemonSaveIntervalSeconds = 30
|
||||
|
||||
@CobblemonConfigField(Category.Storage, lang = "storage_format", SERVER)
|
||||
@CobblemonConfigField(Category.Storage, lang = "storage_format")
|
||||
var storageFormat = "nbt"
|
||||
|
||||
@CobblemonConfigField(Category.Storage, lang = "prevent_complete_party_deposit", SERVER)
|
||||
@CobblemonConfigField(Category.Storage, lang = "prevent_complete_party_deposit")
|
||||
var preventCompletePartyDeposit = false
|
||||
|
||||
@CobblemonConfigField(Category.Storage, lang = "mongo_db_connection_string", SERVER)
|
||||
@CobblemonConfigField(Category.Storage, lang = "mongo_db_connection_string")
|
||||
var mongoDBConnectionString = "mongodb://localhost:27017"
|
||||
@CobblemonConfigField(Category.Storage, lang = "mongo_db_database_name", SERVER)
|
||||
@CobblemonConfigField(Category.Storage, lang = "mongo_db_database_name")
|
||||
var mongoDBDatabaseName = "cobblemon"
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_vertical_correction_blocks", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_vertical_correction_blocks")
|
||||
@IntConstraint(min = 1, max = 200)
|
||||
var maxVerticalCorrectionBlocks = 64
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_level_range_max", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_level_range_max")
|
||||
@IntConstraint(min = 1, max = 1000)
|
||||
var minimumLevelRangeMax = 10
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "enable_spawning", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "enable_spawning")
|
||||
var enableSpawning = true
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_distance_between_entities", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_distance_between_entities")
|
||||
var minimumDistanceBetweenEntities = 8.0
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_nearby_blocks_horizontal_range", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_nearby_blocks_horizontal_range")
|
||||
var maxNearbyBlocksHorizontalRange = 4
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_nearby_blocks_vertical_range", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_nearby_blocks_vertical_range")
|
||||
var maxNearbyBlocksVerticalRange = 2
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_vertical_space", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "max_vertical_space")
|
||||
var maxVerticalSpace = 8
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "spawning_zone_diameter", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "spawning_zone_diameter")
|
||||
@SerializedName("spawningZoneDiameter", alternate = ["worldSliceDiameter"])
|
||||
var spawningZoneDiameter = 8
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "spawning_zone_height", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "spawning_zone_height")
|
||||
@SerializedName("spawningZoneHeight", alternate = ["worldSliceHeight"])
|
||||
var spawningZoneHeight = 16
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "ticks_between_spawn_attempts", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "ticks_between_spawn_attempts")
|
||||
var ticksBetweenSpawnAttempts = 20F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_spawning_zone_distance_from_player", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_spawning_zone_distance_from_player")
|
||||
@SerializedName("minimumSpawningZoneDistanceFromPlayer", alternate = ["minimumSliceDistanceFromPlayer"])
|
||||
var minimumSpawningZoneDistanceFromPlayer = 16F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "maximum_spawning_zone_distance_from_player", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "maximum_spawning_zone_distance_from_player")
|
||||
@SerializedName("maximumSpawningZoneDistanceFromPlayer", alternate = ["maximumSliceDistanceFromPlayer"])
|
||||
var maximumSpawningZoneDistanceFromPlayer = 16 * 4F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "maximum_spawns_per_pass", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "maximum_spawns_per_pass")
|
||||
var maximumSpawnsPerPass = 8
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "export_spawn_config", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "export_spawn_config")
|
||||
var exportSpawnConfig = false
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "save_pokemon_to_world", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "save_pokemon_to_world")
|
||||
var savePokemonToWorld = true
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "export_starter_config", SERVER)
|
||||
@CobblemonConfigField(Category.Starter, lang = "export_starter_config")
|
||||
var exportStarterConfig = false
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "auto_update_showdown", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "auto_update_showdown")
|
||||
var autoUpdateShowdown = true
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "default_flee_distance", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "default_flee_distance")
|
||||
var defaultFleeDistance = 16F * 2
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "allow_experience_from_pvp", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "allow_experience_from_pvp")
|
||||
var allowExperienceFromPvP = true
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "experience_share_multiplier", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "experience_share_multiplier")
|
||||
var experienceShareMultiplier = .5
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "lucky_egg_multiplier", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "lucky_egg_multiplier")
|
||||
var luckyEggMultiplier = 1.5
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "allow_spectating", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "allow_spectating")
|
||||
var allowSpectating = true
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "experience_multiplier", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "experience_multiplier")
|
||||
var experienceMultiplier = 2F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "pokemon_per_chunk", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "pokemon_per_chunk")
|
||||
var pokemonPerChunk = 1F
|
||||
|
||||
@CobblemonConfigField(Category.PassiveStatus, lang = "passive_statuses", SERVER)
|
||||
@CobblemonConfigField(Category.PassiveStatus, lang = "passive_statuses")
|
||||
var passiveStatuses = mutableMapOf(
|
||||
Statuses.POISON.configEntry(),
|
||||
Statuses.POISON_BADLY.configEntry(),
|
||||
@@ -165,165 +163,165 @@ class CobblemonConfig {
|
||||
Statuses.BURN.configEntry()
|
||||
)
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "infinite_healer_charge", SERVER)
|
||||
@CobblemonConfigField(Category.Healing, lang = "infinite_healer_charge")
|
||||
var infiniteHealerCharge = false
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "max_healer_charge", SERVER)
|
||||
@CobblemonConfigField(Category.Healing, lang = "max_healer_charge")
|
||||
var maxHealerCharge = 6.0f
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "seconds_to_charge_healing_machine", SERVER)
|
||||
@CobblemonConfigField(Category.Healing, lang = "seconds_to_charge_healing_machine")
|
||||
var secondsToChargeHealingMachine = 900.0
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "default_faint_timer", SERVER)
|
||||
@CobblemonConfigField(Category.Healing, lang = "default_faint_timer")
|
||||
var defaultFaintTimer = 300
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "faint_awaken_health_percent", SERVER)
|
||||
@CobblemonConfigField(Category.Healing, lang = "faint_awaken_health_percent")
|
||||
var faintAwakenHealthPercent = 0.2f
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "heal_percent", SERVER)
|
||||
@CobblemonConfigField(Category.Healing, lang = "heal_percent")
|
||||
var healPercent = 0.05
|
||||
|
||||
@CobblemonConfigField(Category.Healing, lang = "heal_timer", SERVER)
|
||||
@CobblemonConfigField(Category.Healing, lang = "heal_timer")
|
||||
var healTimer = 60
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "base_apricorn_tree_generation_chance", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "base_apricorn_tree_generation_chance")
|
||||
var baseApricornTreeGenerationChance = 0.1F
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_level_label", CLIENT)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_level_label")
|
||||
var displayEntityLevelLabel = true
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_name_label", CLIENT)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_name_label")
|
||||
var displayEntityNameLabel = true
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_name_for_unknown_pokemon", CLIENT)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_name_for_unknown_pokemon")
|
||||
var displayNameForUnknownPokemon = false
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_labels_when_crouching_only", CLIENT)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "display_entity_labels_when_crouching_only")
|
||||
var displayEntityLabelsWhenCrouchingOnly = false
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "shiny_rate", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "shiny_rate")
|
||||
var shinyRate = 8192F
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "shiny_notice_particles_distance", CLIENT)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "shiny_notice_particles_distance")
|
||||
var shinyNoticeParticlesDistance = 24F
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "capture_calculator", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "capture_calculator")
|
||||
var captureCalculator: CaptureCalculator = CobblemonCaptureCalculator
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "player_damage_pokemon", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "player_damage_pokemon")
|
||||
var playerDamagePokemon = true
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "apple_leftovers_chance", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "apple_leftovers_chance")
|
||||
var appleLeftoversChance = 0.025
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "max_roots_in_area", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "max_roots_in_area")
|
||||
var maxRootsInArea = 5
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "big_root_propagation_chance", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "big_root_propagation_chance")
|
||||
var bigRootPropagationChance = 0.1
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "energy_root_chance", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "energy_root_chance")
|
||||
var energyRootChance = 0.25
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_dynamax_level", SERVER)
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "max_dynamax_level")
|
||||
@IntConstraint(min = 0, max = 10)
|
||||
var maxDynamaxLevel = 10
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "tera_type_rate", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "tera_type_rate")
|
||||
var teraTypeRate = 20F
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "default_pastured_pokemon_limit", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "default_pastured_pokemon_limit")
|
||||
var defaultPasturedPokemonLimit = 16
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_block_update_ticks", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_block_update_ticks")
|
||||
var pastureBlockUpdateTicks = 40
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_max_wander_distance", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_max_wander_distance")
|
||||
var pastureMaxWanderDistance = 64
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_max_per_chunk", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "pasture_max_per_chunk")
|
||||
var pastureMaxPerChunk = 4F
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "max_inserted_fossil_items", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "max_inserted_fossil_items")
|
||||
var maxInsertedFossilItems = 2
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "walking_in_battle_animations", CLIENT)
|
||||
@CobblemonConfigField(Category.Battles, lang = "walking_in_battle_animations")
|
||||
var walkingInBattleAnimations = false
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_wild_max_distance", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_wild_max_distance")
|
||||
var battleWildMaxDistance = 12F
|
||||
|
||||
@CobblemonConfigField(Category.World, lang = "trade_max_distance", SERVER)
|
||||
@CobblemonConfigField(Category.World, lang = "trade_max_distance")
|
||||
var tradeMaxDistance = 12F
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_pvp_max_distance", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_pvp_max_distance")
|
||||
@SerializedName("battlePvPMaxDistance", alternate = ["BattlePvPMaxDistance"])
|
||||
var battlePvPMaxDistance = 32F
|
||||
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_spectate_max_distance", SERVER)
|
||||
@CobblemonConfigField(Category.Battles, lang = "battle_spectate_max_distance")
|
||||
var battleSpectateMaxDistance = 64F
|
||||
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "max_pokedex_scanning_detection_range", SERVER)
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "max_pokedex_scanning_detection_range")
|
||||
var maxPokedexScanningDetectionRange = 10.0
|
||||
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "hide_unimplemented_pokemon_in_the_pokedex", CLIENT)
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "hide_unimplemented_pokemon_in_the_pokedex")
|
||||
var hideUnimplementedPokemonInThePokedex = false
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "summary_pokemon_follow_cursor", CLIENT)
|
||||
@CobblemonConfigField(Category.Interface, lang = "summary_pokemon_follow_cursor")
|
||||
var summaryPokemonFollowCursor = true
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "party_portrait_animations", CLIENT)
|
||||
@CobblemonConfigField(Category.Interface, lang = "party_portrait_animations")
|
||||
var partyPortraitAnimations = PortraitStyle.NEVER_ANIMATE
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "third_person_view_bobbing", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "third_person_view_bobbing")
|
||||
var thirdPersonViewBobbing = true
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_roll", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_roll")
|
||||
var invertRoll = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_pitch", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_pitch")
|
||||
var invertPitch = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_yaw", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "invert_yaw")
|
||||
var invertYaw = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "x_axis_sensitivity", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "x_axis_sensitivity")
|
||||
var xAxisSensitivity = 1.0
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "y_axis_sensitivity", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "y_axis_sensitivity")
|
||||
var yAxisSensitivity = 1.0
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "swap_x_and_y_axes", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "swap_x_and_y_axes")
|
||||
var swapXAndYAxes = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "automatic_righting_delay", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "automatic_righting_delay")
|
||||
var rightingDelay = -1.0
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "disable_roll", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "disable_roll")
|
||||
var disableRoll = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "display_controls_duration_seconds", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "display_controls_duration_seconds")
|
||||
var displayControlSeconds = 3
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "infinite_ride_stamina", SERVER)
|
||||
@CobblemonConfigField(Category.Riding, lang = "infinite_ride_stamina")
|
||||
var infiniteRideStamina = false
|
||||
|
||||
@CobblemonConfigField(Category.Riding, lang = "remember_riding_camera", CLIENT)
|
||||
@CobblemonConfigField(Category.Riding, lang = "remember_riding_camera")
|
||||
var rememberRidingCamera = true
|
||||
|
||||
@CobblemonConfigField(Category.Debug, lang = "enable_debug_keys", CLIENT)
|
||||
@CobblemonConfigField(Category.Debug, lang = "enable_debug_keys")
|
||||
var enableDebugKeys = true
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_near_distance", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_near_distance")
|
||||
var despawnerNearDistance = 32f
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_far_distance", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_far_distance")
|
||||
var despawnerFarDistance = 96f
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_min_age_ticks", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_min_age_ticks")
|
||||
var despawnerMinAgeTicks = 600
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_max_age_ticks", SERVER)
|
||||
@CobblemonConfigField(Category.Spawning, lang = "despawner_max_age_ticks")
|
||||
var despawnerMaxAgeTicks = 3600
|
||||
|
||||
fun clone(): CobblemonConfig {
|
||||
|
||||
@@ -13,10 +13,4 @@ package com.cobblemon.mod.common.config
|
||||
annotation class CobblemonConfigField(
|
||||
val category: Category,
|
||||
val lang: String,
|
||||
val side: CobblemonConfigSide,
|
||||
) {
|
||||
enum class CobblemonConfigSide {
|
||||
CLIENT,
|
||||
SERVER,
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -10,9 +10,8 @@ package com.cobblemon.mod.common.config.starter
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.config.Category
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField.CobblemonConfigSide.SERVER
|
||||
import com.cobblemon.mod.common.config.LastChangedVersion
|
||||
import com.cobblemon.mod.common.config.CobblemonConfigField
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.google.gson.GsonBuilder
|
||||
|
||||
@@ -25,17 +24,17 @@ class StarterConfig {
|
||||
.create()
|
||||
}
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "allow_starter_on_join", SERVER)
|
||||
@CobblemonConfigField(Category.Starter, lang = "allow_starter_on_join")
|
||||
var allowStarterOnJoin = true
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "prompt_starter_once_only", SERVER)
|
||||
@CobblemonConfigField(Category.Starter, lang = "prompt_starter_once_only")
|
||||
@LastChangedVersion("1.5.0")
|
||||
var promptStarterOnceOnly = true
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "use_config_starters", SERVER)
|
||||
@CobblemonConfigField(Category.Starter, lang = "use_config_starters")
|
||||
var useConfigStarters = false
|
||||
|
||||
@CobblemonConfigField(Category.Starter, lang = "starters", SERVER)
|
||||
@CobblemonConfigField(Category.Starter, lang = "starters")
|
||||
var starters = mutableListOf(
|
||||
StarterCategory(
|
||||
name = "Kanto",
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.cobblemon.mod.common.debug
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.debug.DebugRenderer
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Position
|
||||
import java.util.function.Consumer
|
||||
|
||||
object RidingDebugRenderer : DebugRenderer.SimpleDebugRenderer {
|
||||
var enabled = false
|
||||
|
||||
override fun render(
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
camX: Double,
|
||||
camY: Double,
|
||||
camZ: Double
|
||||
) {
|
||||
val minecraft = Minecraft.getInstance() ?: return
|
||||
val vehicle = minecraft.player?.vehicle
|
||||
if (vehicle != null && vehicle is PokemonEntity) {
|
||||
DebugRenderer.renderFloatingText(poseStack, buffer, "riding", camX, camY, camZ, -1, 1f, false, 0.5f, true)
|
||||
renderRidingInfo(vehicle, poseStack, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderRidingInfo(vehicle: PokemonEntity, poseStack: PoseStack, buffer: MultiBufferSource) {
|
||||
val ridingController = vehicle.ridingController
|
||||
if (ridingController != null) {
|
||||
var i = 0
|
||||
ridingController.context?.let { context ->
|
||||
val debugString = "Currently active: ${context.behaviour}"
|
||||
renderTextOverVehicle(poseStack, buffer, vehicle.position(), i, debugString, -1, 0.03f)
|
||||
i++
|
||||
}
|
||||
ridingController.behaviours.forEach { (style, settings) ->
|
||||
val debugString = "Available: $style"
|
||||
renderTextOverVehicle(poseStack, buffer, vehicle.position(), i, debugString, -1, 0.03f)
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderTextOverVehicle(poseStack: PoseStack, buffer: MultiBufferSource, pos: Position, layer: Int, text: String, color: Int, scale: Float) {
|
||||
val blockPos = BlockPos.containing(pos)
|
||||
val x = blockPos.x.toDouble() + 0.5
|
||||
val y = blockPos.y.toDouble() + 2.4 + layer * 0.25
|
||||
val z = blockPos.z.toDouble() + 0.5
|
||||
DebugRenderer.renderFloatingText(poseStack, buffer, text, x, y, z, color, scale, false, 0.5f, true)
|
||||
}
|
||||
|
||||
fun clientHandler(enabled: Boolean) {
|
||||
this.enabled = enabled
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ interface OmniPathingEntity {
|
||||
fun canSwimInLava(): Boolean
|
||||
fun canWalkOnLava(): Boolean
|
||||
fun canSwimUnderFluid(fluidState: FluidState): Boolean
|
||||
fun canPathThroughSaccLeaves(): Boolean
|
||||
fun canFly(): Boolean
|
||||
fun isFlying(): Boolean
|
||||
fun setFlying(state: Boolean)
|
||||
|
||||
@@ -8,16 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.entity.ai
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.entity.OmniPathingEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
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
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.tags.FluidTags
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
@@ -184,9 +181,7 @@ class OmniPathNavigation(val world: Level, val entity: Mob) : GroundPathNavigati
|
||||
target = blockPos
|
||||
}
|
||||
|
||||
val blockState = this.world.getBlockState(target)
|
||||
val path = if (!blockState.isSolid
|
||||
|| (blockState.`is`(BlockTags.LEAVES) && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES && (this.entity as PokemonEntity).canPathThroughSaccLeaves())) {
|
||||
val path = if (!this.world.getBlockState(target).isSolid) {
|
||||
findPath(target, distance)
|
||||
} else {
|
||||
blockPos = target.above()
|
||||
@@ -269,9 +264,6 @@ 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
|
||||
}
|
||||
if (world.getBlockState(blockPos).block == CobblemonBlocks.SACCHARINE_LEAVES && (this.entity as PokemonEntity).canPathThroughSaccLeaves()) {
|
||||
return vec.y + 0.5
|
||||
}
|
||||
return if ((canFloat()) && blockGetter.getFluidState(blockPos).`is`(FluidTags.WATER)) vec.y + 0.5 else super.getGroundY(vec)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.entity.npc
|
||||
import com.cobblemon.mod.common.CobblemonBehaviours
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.config.AddVariablesConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.ApplyBehaviours
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.npc.NPCClass
|
||||
@@ -23,7 +22,6 @@ object NPCBrain {
|
||||
if (npcEntity.behavioursAreCustom) {
|
||||
behaviourConfigurations = listOf(ApplyBehaviours().apply { behaviours.addAll(npcEntity.behaviours) })
|
||||
}
|
||||
behaviourConfigurations = behaviourConfigurations + AddVariablesConfig(npcClass.config)
|
||||
|
||||
val ctx = BehaviourConfigurationContext()
|
||||
ctx.addMemories(CobblemonMemories.DIALOGUES)
|
||||
|
||||
@@ -708,10 +708,6 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canPathThroughSaccLeaves(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canFly(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
+2
-2
@@ -393,8 +393,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
|
||||
private fun breakFree() {
|
||||
val pokemon = capturingPokemon ?: return
|
||||
pokemon.setPositionSafely(position())
|
||||
|
||||
pokemon.setPos(position())
|
||||
pokemon.beamMode = 2
|
||||
pokemon.isInvisible = false
|
||||
pokemon.isSilent = false
|
||||
@@ -491,6 +490,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
|
||||
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)
|
||||
|
||||
@@ -18,7 +18,6 @@ import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.drop.DropTable
|
||||
import com.cobblemon.mod.common.api.entity.Despawner
|
||||
@@ -166,7 +165,6 @@ import net.minecraft.world.entity.ai.attributes.AttributeSupplier
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes
|
||||
import net.minecraft.world.entity.ai.control.MoveControl
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
import net.minecraft.world.entity.animal.Animal
|
||||
@@ -1188,7 +1186,6 @@ open class PokemonEntity(
|
||||
if (!this.canRide(player)) return@ifRidingAvailableSupply false
|
||||
if (tethering != null) return@ifRidingAvailableSupply false
|
||||
if (seats.isEmpty()) return@ifRidingAvailableSupply false
|
||||
if ((owner as? ServerPlayer)?.isInBattle() == true) return@ifRidingAvailableSupply false
|
||||
if (this.owner != player && this.passengers.isEmpty()) return@ifRidingAvailableSupply false
|
||||
return@ifRidingAvailableSupply behaviour.isActive(settings, state, this)
|
||||
}
|
||||
@@ -1247,19 +1244,11 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
override fun checkDespawn() {
|
||||
if (pokemon.getOwnerUUID() == null && !isPersistenceRequired && despawner.shouldDespawn(this) ) {
|
||||
if (pokemon.getOwnerUUID() == null && !isPersistenceRequired && (!this.pokemon.canDropHeldItem || this.pokemon.heldItem.isEmpty) && despawner.shouldDespawn(this) ) {
|
||||
discard()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isPersistenceRequired(): Boolean {
|
||||
return super.isPersistenceRequired()
|
||||
|| (this.pokemon.canDropHeldItem && !this.pokemon.heldItem.isEmpty)
|
||||
|| this.brain.checkMemory(CobblemonMemories.HIVE_LOCATION, MemoryStatus.VALUE_PRESENT)
|
||||
|| this.brain.checkMemory(CobblemonMemories.HIVE_COOLDOWN, MemoryStatus.VALUE_PRESENT)
|
||||
|| this.brain.checkMemory(CobblemonMemories.NEARBY_SACC_LEAVES, MemoryStatus.VALUE_PRESENT)
|
||||
}
|
||||
|
||||
fun setBehaviourFlag(flag: PokemonBehaviourFlag, on: Boolean) {
|
||||
entityData.set(BEHAVIOUR_FLAGS, setBitForByte(entityData.get(BEHAVIOUR_FLAGS), flag.bit, on))
|
||||
}
|
||||
@@ -2188,19 +2177,9 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
this.yRotO = this.yRot
|
||||
val rotation = behaviour.rotation(settings, state, this, driver)
|
||||
|
||||
if (this is OrientationControllable) {
|
||||
val controller = this.orientationController
|
||||
if (!controller.isActive()) {
|
||||
val rotation = behaviour.rotation(settings, state, this, driver)
|
||||
// TODO: Find a better solution than setting the vehicle xrot to zero.
|
||||
// The problem is that nothing actually effects the vehicle/pokemon xrot so when it gets set to
|
||||
// -45 degrees by a rollable ride controller it gets saved off and not modified until you try
|
||||
// and takeoff again. And at that point you snap to -45 pitch in the orientationControllers matrix
|
||||
setRot(rotation.y, 0.0f)
|
||||
}
|
||||
}
|
||||
|
||||
setRot(rotation.y, rotation.x)
|
||||
this.yHeadRot = this.yRot
|
||||
this.yBodyRot = this.yRot
|
||||
this.passengers.filterIsInstance<LivingEntity>()
|
||||
@@ -2321,12 +2300,6 @@ open class PokemonEntity(
|
||||
return loc.compareTo(resourceLocation) == 0
|
||||
}
|
||||
|
||||
fun applyRenderRotation(partialTicks: Float) {
|
||||
ifRidingAvailable { behaviour, settings, state ->
|
||||
behaviour.applyRenderRotation(settings, state, this, partialTicks)
|
||||
}
|
||||
}
|
||||
|
||||
var jumpInputStrength: Int = 0 // move this
|
||||
override fun onPlayerJump(strength: Int) {
|
||||
// See if this controls the hot bar element
|
||||
@@ -2457,7 +2430,6 @@ open class PokemonEntity(
|
||||
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 canPathThroughSaccLeaves() = this.config.getMap().getOrDefault("can_path_through_sacc_leaves", DoubleValue.ZERO).asDouble() == 1.0
|
||||
override fun canWalkOnLava() = exposedForm.behaviour.moving.swim.canWalkOnLava
|
||||
override fun entityOnGround() = onGround()
|
||||
|
||||
|
||||
+40
-50
@@ -9,22 +9,17 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.sensors
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.tags.PoiTypeTags
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiManager
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiRecord
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.BeehiveBlock
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
|
||||
|
||||
class BeeHiveSensor : Sensor<PokemonEntity>(300) {
|
||||
override fun requires() = setOf(CobblemonMemories.HIVE_LOCATION, CobblemonMemories.HIVE_BLACKLIST)
|
||||
override fun requires() = setOf(CobblemonMemories.HIVE_LOCATION)
|
||||
override fun doTick(world: ServerLevel, entity: PokemonEntity) {
|
||||
val brain = entity.brain
|
||||
val currentHive = brain.getMemory(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
@@ -32,30 +27,35 @@ class BeeHiveSensor : Sensor<PokemonEntity>(300) {
|
||||
if (currentHive != null) {
|
||||
val state = world.getBlockState(currentHive)
|
||||
|
||||
if (!isValidHive(state) || !hasReachableAdjacentSide(world, currentHive)) {
|
||||
if (!isValidHiveOrLeaf(state) || !hasReachableAdjacentSide(world, entity, currentHive)) {
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
} else if (isAtMaxHoney(state)) {
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
} else {
|
||||
return // We already have a valid hive, no need to search for another
|
||||
}
|
||||
}
|
||||
|
||||
// Search for nearest hive/nest
|
||||
val searchRadius = 16 // is this too big for us to use?
|
||||
val centerPos = entity.blockPosition()
|
||||
|
||||
var closestHivePos: BlockPos? = null
|
||||
var closestDistance = Double.MAX_VALUE
|
||||
|
||||
val list = findNearbyHivesWithSpace(entity)
|
||||
BlockPos.betweenClosedStream(
|
||||
centerPos.offset(-searchRadius, -2, -searchRadius),
|
||||
centerPos.offset(searchRadius, 2, searchRadius)
|
||||
).forEach { pos ->
|
||||
val state = world.getBlockState(pos)
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
val blackList = brain.getMemory(CobblemonMemories.HIVE_BLACKLIST).orElse(emptyList())
|
||||
for (blockPos in list) {
|
||||
if (blackList.contains(blockPos)) continue
|
||||
if (hasReachableAdjacentSide(world, blockPos)) {
|
||||
closestHivePos = blockPos
|
||||
break
|
||||
if (isValidHiveOrLeaf(state) && !isAtMaxHoney(state) && hasReachableAdjacentSide(world, entity, pos)) {
|
||||
val distance = pos.distToCenterSqr(centerPos.x + 0.5, centerPos.y + 0.5, centerPos.z + 0.5)
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance
|
||||
closestHivePos = pos.immutable()
|
||||
}
|
||||
}
|
||||
if (closestHivePos == null) {
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_BLACKLIST)
|
||||
closestHivePos = list.first()
|
||||
}
|
||||
}
|
||||
|
||||
if (closestHivePos != null) {
|
||||
@@ -63,47 +63,37 @@ class BeeHiveSensor : Sensor<PokemonEntity>(300) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidHive(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return isHiveBlock(state)
|
||||
private fun isAtMaxHoney(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return when {
|
||||
isHiveBlock(state) -> state.getValue(BeehiveBlock.HONEY_LEVEL) == BeehiveBlock.MAX_HONEY_LEVELS
|
||||
isSaccharineLeafBlock(state) -> state.getValue(SaccharineLeafBlock.AGE) == SaccharineLeafBlock.MAX_AGE
|
||||
else -> true // Unknown block type
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidHiveOrLeaf(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return isHiveBlock(state) || isSaccharineLeafBlock(state)
|
||||
}
|
||||
|
||||
private fun isSaccharineLeafBlock(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return state.block is SaccharineLeafBlock
|
||||
}
|
||||
|
||||
private fun isHiveBlock(state: net.minecraft.world.level.block.state.BlockState): Boolean {
|
||||
return state.`is`(Blocks.BEEHIVE) || state.`is`(Blocks.BEE_NEST)
|
||||
}
|
||||
|
||||
private fun hasReachableAdjacentSide(world: ServerLevel, pos: BlockPos): Boolean {
|
||||
private fun hasReachableAdjacentSide(world: ServerLevel, entity: PokemonEntity, pos: BlockPos): Boolean {
|
||||
for (dir in Direction.entries) {
|
||||
val adjacentPos = pos.relative(dir)
|
||||
if (world.isEmptyBlock(adjacentPos)) {
|
||||
return true
|
||||
val nav = entity.navigation
|
||||
val path = nav.createPath(adjacentPos, 0)
|
||||
if (path != null && path.canReach()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun findNearbyHivesWithSpace(entity: PokemonEntity): List<BlockPos> {
|
||||
val blockPos = entity.blockPosition()
|
||||
val poiManager = (entity.level() as ServerLevel).poiManager
|
||||
val stream = poiManager.getInRange(
|
||||
{ holder -> holder.`is`(PoiTypeTags.BEE_HOME) },
|
||||
blockPos,
|
||||
20,
|
||||
PoiManager.Occupancy.ANY
|
||||
)
|
||||
return stream
|
||||
.map(PoiRecord::getPos)
|
||||
.filter { pos -> doesHiveHaveSpace(pos, entity.level()) }
|
||||
.sorted { pos1, pos2 -> pos1.distSqr(blockPos).toInt() - pos2.distSqr(blockPos).toInt() }
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun doesHiveHaveSpace(hivePos: BlockPos, world: Level): Boolean {
|
||||
val blockEntity: BlockEntity? = world.getBlockEntity(hivePos)
|
||||
if (blockEntity is BeehiveBlockEntity) {
|
||||
return !blockEntity.isFull
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-43
@@ -10,73 +10,46 @@ package com.cobblemon.mod.common.entity.pokemon.ai.sensors
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.distanceTo
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Vec3i
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.DoublePlantBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
|
||||
|
||||
class FlowerSensor : Sensor<PokemonEntity>(120) {
|
||||
|
||||
override fun requires() = setOf(CobblemonMemories.NEARBY_FLOWER)
|
||||
override fun requires() = setOf(CobblemonMemories.NEARBY_FLOWERS)
|
||||
|
||||
override fun doTick(world: ServerLevel, entity: PokemonEntity) {
|
||||
val brain = entity.brain
|
||||
|
||||
// Check curr memory
|
||||
val currPos = brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER).orElse(null)
|
||||
if (currPos != null && isFlower(entity.level().getBlockState(currPos)) && entity.distanceTo(currPos) <= 32) {
|
||||
return
|
||||
}
|
||||
|
||||
val searchRadius = 5
|
||||
val searchRadius = 32
|
||||
val centerPos = entity.blockPosition()
|
||||
var flowerPos: BlockPos? = null
|
||||
var shortestDist = Double.MAX_VALUE
|
||||
val flowers = mutableListOf<BlockPos>()
|
||||
|
||||
BlockPos.betweenClosedStream(
|
||||
centerPos.offset(-searchRadius, -2, -searchRadius),
|
||||
centerPos.offset(searchRadius, 2, searchRadius)
|
||||
).forEach { pos ->
|
||||
val state = world.getBlockState(pos)
|
||||
if (isFlower(state)) {
|
||||
val distance = pos.distSqr(Vec3i(centerPos.x, centerPos.y, centerPos.z))
|
||||
if (distance < shortestDist) {
|
||||
flowerPos = BlockPos(pos)
|
||||
shortestDist = distance
|
||||
}
|
||||
if (isFlower(state) && isPathfindableTo(entity, pos)) {
|
||||
flowers += pos.immutable()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (flowerPos != null) {
|
||||
brain.setMemory(CobblemonMemories.NEARBY_FLOWER, flowerPos)
|
||||
if (!flowers.isEmpty()) {
|
||||
brain.setMemory(CobblemonMemories.NEARBY_FLOWERS, flowers)
|
||||
} else {
|
||||
brain.eraseMemory(CobblemonMemories.NEARBY_FLOWER)
|
||||
brain.eraseMemory(CobblemonMemories.NEARBY_FLOWERS)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isFlower(state: BlockState): Boolean {
|
||||
// Borrowed from Bee.class
|
||||
if (state.hasProperty(BlockStateProperties.WATERLOGGED) && state.getValue(
|
||||
BlockStateProperties.WATERLOGGED
|
||||
) as Boolean
|
||||
) {
|
||||
return false
|
||||
} else if (state.`is`(BlockTags.FLOWERS)) {
|
||||
if (state.`is`(Blocks.SUNFLOWER)) {
|
||||
return state.getValue(DoublePlantBlock.HALF) == DoubleBlockHalf.UPPER
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return state.`is`(BlockTags.FLOWERS)
|
||||
}
|
||||
|
||||
private fun isPathfindableTo(entity: PokemonEntity, pos: BlockPos): Boolean {
|
||||
val nav = entity.navigation
|
||||
val path = nav.createPath(pos, 0)
|
||||
return path != null && path.canReach()
|
||||
}
|
||||
}
|
||||
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.sensors
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.distanceTo
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Vec3i
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.ai.sensing.Sensor
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import kotlin.time.measureTime
|
||||
|
||||
class SacLeavesSensor : Sensor<PokemonEntity>(120) {
|
||||
|
||||
override fun requires() = setOf(CobblemonMemories.NEARBY_SACC_LEAVES)
|
||||
|
||||
override fun doTick(world: ServerLevel, entity: PokemonEntity) {
|
||||
val brain = entity.brain
|
||||
|
||||
val searchRadius = 7
|
||||
val tooFarDistance = 30
|
||||
val wayTooFarDistance = 64
|
||||
val currPos: BlockPos? = brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
|
||||
if (currPos != null && isValidLeafBlock(entity.level().getBlockState(currPos))) {
|
||||
val distance = entity.distanceTo(currPos)
|
||||
if (distance <= tooFarDistance) {
|
||||
return
|
||||
} else if (distance > wayTooFarDistance) {
|
||||
brain.eraseMemory(CobblemonMemories.NEARBY_SACC_LEAVES)
|
||||
}
|
||||
}
|
||||
|
||||
val centerPos = entity.blockPosition()
|
||||
var leavesPos: BlockPos? = null
|
||||
var shortestDist = Double.MAX_VALUE
|
||||
BlockPos.betweenClosedStream(
|
||||
centerPos.offset(-searchRadius, -2, -searchRadius),
|
||||
centerPos.offset(searchRadius, searchRadius, searchRadius)
|
||||
).forEach { pos ->
|
||||
val state = world.getBlockState(pos)
|
||||
if (isValidLeafBlock(state)) {
|
||||
val distance = pos.distSqr(Vec3i(centerPos.x, centerPos.y, centerPos.z))
|
||||
if (distance < shortestDist) {
|
||||
leavesPos = BlockPos(pos)
|
||||
shortestDist = distance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (leavesPos != null) {
|
||||
brain.setMemory(CobblemonMemories.NEARBY_SACC_LEAVES, leavesPos)
|
||||
} else {
|
||||
brain.eraseMemory(CobblemonMemories.NEARBY_SACC_LEAVES)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidLeafBlock(state: BlockState): Boolean {
|
||||
if (state.block !is SaccharineLeafBlock) return false
|
||||
if (state.hasProperty(BlockStateProperties.WATERLOGGED) && state.getValue(
|
||||
BlockStateProperties.WATERLOGGED
|
||||
) as Boolean
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return state.getValue(SaccharineLeafBlock.AGE) != SaccharineLeafBlock.MAX_AGE
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.OneShot
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object PathToBeeHiveTask {
|
||||
|
||||
fun create(): OneShot<in LivingEntity> {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.POLLINATED),
|
||||
it.present(CobblemonMemories.HIVE_LOCATION),
|
||||
it.absent(CobblemonMemories.HIVE_COOLDOWN)
|
||||
).apply(it) { lookTarget, walkTarget, pollinated, hiveMemory, hiveCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val hiveLocation = it.get(hiveMemory)
|
||||
val sidesByClosest = listOf(
|
||||
hiveLocation.north(),
|
||||
hiveLocation.south(),
|
||||
hiveLocation.east(),
|
||||
hiveLocation.west()
|
||||
).sortedBy { it.distSqr(entity.blockPosition()) }
|
||||
|
||||
var openSide = BlockPos.ZERO
|
||||
for (side in sidesByClosest) {
|
||||
if (world.getBlockState(side).isAir) {
|
||||
openSide = side
|
||||
break
|
||||
}
|
||||
}
|
||||
if (openSide == BlockPos.ZERO) {
|
||||
if (world.getBlockState(hiveLocation.above()).isAir) {
|
||||
// If the above position is also air, we can use it
|
||||
openSide = hiveLocation.above() // Fallback to above if no open sides found
|
||||
} else if (world.getBlockState(hiveLocation.below()).isAir) {
|
||||
// If the below position is also air, we can use it
|
||||
openSide = hiveLocation.below() // Fallback to below if no open sides found
|
||||
} else {
|
||||
// If no open sides or above/below positions are found, we cannot proceed
|
||||
return@Trigger false
|
||||
}
|
||||
}
|
||||
val targetVec = Vec3.atCenterOf(openSide)
|
||||
|
||||
// Set path target toward hive
|
||||
walkTarget.set(WalkTarget(targetVec, 0.35F, 0))
|
||||
lookTarget.set(BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-12
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
@@ -21,26 +20,31 @@ import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object PathToFlowerTask {
|
||||
|
||||
|
||||
fun create(): OneShot<in LivingEntity> {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.NEARBY_FLOWER),
|
||||
it.registered(CobblemonMemories.HAS_NECTAR),
|
||||
it.absent(CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN),
|
||||
it.present(CobblemonMemories.NEARBY_FLOWERS),
|
||||
it.absent(CobblemonMemories.POLLINATED),
|
||||
it.absent(CobblemonMemories.HIVE_COOLDOWN)
|
||||
).apply(it) { lookTarget, walkTarget, flowerMemory, pollinated, flowerCooldown, hiveCooldown ->
|
||||
).apply(it) { lookTarget, walkTarget, flowerMemory, pollinated, hiveCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive || world.isNight || world.isRaining || entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false)) return@Trigger false
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
val flowerLocations = it.get(flowerMemory).map(Vec3::atCenterOf)
|
||||
if (flowerLocations.isEmpty()) {
|
||||
return@Trigger false
|
||||
}
|
||||
val sortedByDistance = flowerLocations.sortedBy { it.distanceTo(entity.position()) }
|
||||
val closestHalf = sortedByDistance.subList(0, flowerLocations.size / 2 + 1)
|
||||
if (closestHalf.isEmpty()) {
|
||||
return@Trigger false
|
||||
}
|
||||
val targetVec = closestHalf.random()
|
||||
|
||||
val flowerLocation = it.get(flowerMemory)
|
||||
val targetVec = Vec3.atCenterOf(flowerLocation)
|
||||
|
||||
// if we're really close to one then forget it, pollination is gonna occur
|
||||
if (targetVec.distanceToSqr(entity.x, entity.y, entity.z) <= 1.0 ) {
|
||||
if (flowerLocations.any { it.distanceToSqr(entity.x, entity.y, entity.z) <= 1.0 }) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
|
||||
+19
-26
@@ -9,33 +9,31 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.OneShot
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.level.block.BeehiveBlock
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object PlaceHoneyInHiveTask {
|
||||
|
||||
fun create(): OneShot<PokemonEntity> {
|
||||
fun create(): OneShot<in LivingEntity> {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.registered(CobblemonMemories.HAS_NECTAR),
|
||||
it.present(CobblemonMemories.POLLINATED),
|
||||
it.present(CobblemonMemories.HIVE_LOCATION),
|
||||
it.absent(CobblemonMemories.HIVE_COOLDOWN),
|
||||
it.absent(CobblemonMemories.HIVE_COOLDOWN)
|
||||
).apply(it) { walkTarget, pollinated, hiveMemory, hiveCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !wantsToEnterHive(entity)) {
|
||||
if (entity !is PathfinderMob) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val hiveCooldown = 1200L
|
||||
val hiveLocation = it.get(hiveMemory)
|
||||
val targetVec = Vec3.atCenterOf(hiveLocation)
|
||||
|
||||
@@ -47,13 +45,19 @@ object PlaceHoneyInHiveTask {
|
||||
val state = world.getBlockState(hiveLocation)
|
||||
val block = state.block
|
||||
if (block is BeehiveBlock) {
|
||||
val blockEntity = world.getBlockEntity(hiveLocation)
|
||||
if (blockEntity !is BeehiveBlockEntity) return@Trigger false
|
||||
if (blockEntity.isFull) {
|
||||
// Erase Hive memory and give the bee a moment to locate a new hive
|
||||
entity.brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
val currentLevel = state.getValue(BeehiveBlock.HONEY_LEVEL)
|
||||
if (currentLevel < BeehiveBlock.MAX_HONEY_LEVELS) {
|
||||
world.setBlock(hiveLocation, state.setValue(BeehiveBlock.HONEY_LEVEL, currentLevel + 1), 3)
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, hiveCooldown)
|
||||
entity.brain.eraseMemory(CobblemonMemories.POLLINATED)
|
||||
}
|
||||
} else if (block is SaccharineLeafBlock) {
|
||||
val currentAge = state.getValue(SaccharineLeafBlock.AGE)
|
||||
if (currentAge < SaccharineLeafBlock.MAX_AGE) {
|
||||
world.setBlock(hiveLocation, state.setValue(SaccharineLeafBlock.AGE, currentAge + 1), 3)
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, hiveCooldown)
|
||||
entity.brain.eraseMemory(CobblemonMemories.POLLINATED)
|
||||
}
|
||||
blockEntity.addOccupant(entity)
|
||||
}
|
||||
|
||||
return@Trigger true
|
||||
@@ -61,15 +65,4 @@ object PlaceHoneyInHiveTask {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun wantsToEnterHive( entity: PokemonEntity) : Boolean {
|
||||
val result = !entity.brain.checkMemory(CobblemonMemories.HIVE_COOLDOWN, MemoryStatus.VALUE_PRESENT)
|
||||
&& (entity.level().isRaining || entity.level().isNight || entity.brain.getMemory(CobblemonMemories.HAS_NECTAR).orElse(false))
|
||||
if (result) {
|
||||
val blockPos = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
val blockEntity = entity.level().getBlockEntity(blockPos)
|
||||
return blockEntity is BeehiveBlockEntity && !blockEntity.isFireNearby
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
+14
-15
@@ -10,34 +10,33 @@ package com.cobblemon.mod.common.entity.pokemon.ai.tasks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.OneShot
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
|
||||
object PathToSacLeafTask {
|
||||
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
object PollinateFlowerTask {
|
||||
fun create(): OneShot<in LivingEntity> {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.present(CobblemonMemories.NEARBY_FLOWERS),
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.present(CobblemonMemories.HAS_NECTAR),
|
||||
it.present(CobblemonMemories.NEARBY_SACC_LEAVES)
|
||||
).apply(it) { lookTarget, walkTarget, pollinated, saccLeavesPos ->
|
||||
it.absent(CobblemonMemories.POLLINATED),
|
||||
it.absent(CobblemonMemories.HIVE_COOLDOWN)
|
||||
).apply(it) { flowerMemory, walkTarget, pollinated, hiveCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || !entity.isAlive || entity !is PokemonEntity || !it.get(pollinated) || world.isRaining || world.isNight) {
|
||||
return@Trigger false
|
||||
if (entity !is PathfinderMob || !entity.isAlive) return@Trigger false
|
||||
|
||||
val flowerLocations = it.get(flowerMemory)
|
||||
if (flowerLocations.any { it.distSqr(entity.blockPosition()) < 1 }) {
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.POLLINATED, true, 20 * 20L) // 20 seconds to dump the pollen
|
||||
if (entity is PokemonEntity) {
|
||||
entity.pokemon.updateAspects()
|
||||
}
|
||||
}
|
||||
val targetPos = it.get(saccLeavesPos)
|
||||
walkTarget.set(WalkTarget(targetPos, 0.35F, 0))
|
||||
lookTarget.set(BlockPosTracker(targetPos.toVec3d().add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
@@ -102,11 +102,13 @@ class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)
|
||||
if (!canUseOnPokemon(stack, pokemon)) {
|
||||
return InteractionResultHolder.fail(stack)
|
||||
}
|
||||
|
||||
pokemon.feedPokemon(1)
|
||||
|
||||
val boosts = getBoosts(stack, pokemon)
|
||||
pokemon.addRideBoosts(boosts)
|
||||
// Feed the Pokémon 1 fullness point
|
||||
pokemon.feedPokemon(1)
|
||||
|
||||
boosts.forEach { (stat, value) ->
|
||||
pokemon.addRideBoost(stat, value)
|
||||
}
|
||||
|
||||
stack.consume(1, player)
|
||||
|
||||
|
||||
+2
-7
@@ -21,7 +21,6 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineSettings
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
@@ -40,8 +39,7 @@ class RideSettingsSyncPacket(
|
||||
val vehicle: VehicleSettings,
|
||||
val boat: BoatSettings,
|
||||
val burst: BurstSettings,
|
||||
val dolphin: DolphinSettings,
|
||||
val submarine: SubmarineSettings
|
||||
val dolphin: DolphinSettings
|
||||
) : NetworkPacket<RideSettingsSyncPacket> {
|
||||
override val id = ID
|
||||
|
||||
@@ -58,7 +56,6 @@ class RideSettingsSyncPacket(
|
||||
boat.encode(buffer)
|
||||
burst.encode(buffer)
|
||||
dolphin.encode(buffer)
|
||||
submarine.encode(buffer)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -76,8 +73,7 @@ class RideSettingsSyncPacket(
|
||||
vehicle = VehicleSettings(),
|
||||
boat = BoatSettings(),
|
||||
burst = BurstSettings(),
|
||||
dolphin = DolphinSettings(),
|
||||
submarine = SubmarineSettings()
|
||||
dolphin = DolphinSettings()
|
||||
).apply {
|
||||
bird.decode(buffer)
|
||||
glider.decode(buffer)
|
||||
@@ -91,7 +87,6 @@ class RideSettingsSyncPacket(
|
||||
boat.decode(buffer)
|
||||
burst.decode(buffer)
|
||||
dolphin.decode(buffer)
|
||||
submarine.decode(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-7
@@ -15,13 +15,9 @@ import com.cobblemon.mod.common.util.writeMatrix3f
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import org.joml.Matrix3f
|
||||
|
||||
class ServerboundUpdateOrientationPacket internal constructor(
|
||||
val entity: Int,
|
||||
val orientation: Matrix3f?
|
||||
) : NetworkPacket<ServerboundUpdateOrientationPacket> {
|
||||
class ServerboundUpdateOrientationPacket internal constructor(val orientation: Matrix3f?) : NetworkPacket<ServerboundUpdateOrientationPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeInt(entity)
|
||||
buffer.writeBoolean(orientation != null)
|
||||
if (orientation != null) {
|
||||
buffer.writeMatrix3f(orientation)
|
||||
@@ -31,9 +27,8 @@ class ServerboundUpdateOrientationPacket internal constructor(
|
||||
companion object {
|
||||
val ID = cobblemonResource("c2s_update_orientation")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ServerboundUpdateOrientationPacket {
|
||||
val entity = buffer.readInt()
|
||||
val orientation = if (buffer.readBoolean()) buffer.readMatrix3f() else null
|
||||
return ServerboundUpdateOrientationPacket(entity, orientation)
|
||||
return ServerboundUpdateOrientationPacket(orientation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.server.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ServerboundUpdateRiderRotationPacket internal constructor(
|
||||
val riderXRot: Float,
|
||||
val riderYRot: Float,
|
||||
val rideEyePos: Vec3
|
||||
) : NetworkPacket<ServerboundUpdateRiderRotationPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeFloat(riderXRot)
|
||||
buffer.writeFloat(riderYRot)
|
||||
buffer.writeVec3(rideEyePos)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("c2s_update_rider_rotation")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ServerboundUpdateRiderRotationPacket {
|
||||
val riderXRot = buffer.readFloat()
|
||||
val riderYRot = buffer.readFloat()
|
||||
val rideEyePos = buffer.readVec3()
|
||||
return ServerboundUpdateRiderRotationPacket(riderXRot, riderYRot, rideEyePos)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-8
@@ -10,19 +10,15 @@ package com.cobblemon.mod.common.net.serverhandling.orientation
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import kotlin.math.atan2
|
||||
|
||||
object OrientationPacketHandler : ServerNetworkPacketHandler<ServerboundUpdateOrientationPacket> {
|
||||
override fun handle(packet: ServerboundUpdateOrientationPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
val entity = player.level().getEntity(packet.entity) ?: return
|
||||
|
||||
if (entity !is PokemonEntity) return
|
||||
if (entity.controllingPassenger != player) return
|
||||
if (entity !is OrientationControllable) return
|
||||
|
||||
entity.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
if (player is OrientationControllable) {
|
||||
player.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.serverhandling.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.duck.RidePassenger
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object ServerboundUpdateRiderRotationHandler : ServerNetworkPacketHandler<ServerboundUpdateRiderRotationPacket> {
|
||||
|
||||
override fun handle(
|
||||
packet: ServerboundUpdateRiderRotationPacket,
|
||||
server: MinecraftServer,
|
||||
player: ServerPlayer
|
||||
) {
|
||||
if (player is RidePassenger) {
|
||||
player.`cobblemon$setRideXRot`(packet.riderXRot)
|
||||
player.`cobblemon$setRideYRot`(packet.riderYRot)
|
||||
player.`cobblemon$setRideEyePos`(packet.rideEyePos)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1867,40 +1867,19 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
}
|
||||
val max = getMaxRideBoost(stat)
|
||||
rideBoosts[stat] = (getRideBoost(stat) + boostAmount).coerceAtMost(max)
|
||||
onChange(RideBoostsUpdatePacket({ this }, getRideBoosts()))
|
||||
onChange(RideBoostsUpdatePacket({ this }, rideBoosts))
|
||||
return true
|
||||
}
|
||||
|
||||
fun addRideBoosts(boosts: Map<RidingStat, Float>) {
|
||||
var changed = false
|
||||
|
||||
for (boost in boosts) {
|
||||
val (stat, boostAmount) = boost
|
||||
|
||||
if (!canAddRideBoost(stat)) {
|
||||
continue
|
||||
}
|
||||
|
||||
val max = getMaxRideBoost(stat)
|
||||
rideBoosts[stat] = (getRideBoost(stat) + boostAmount).coerceAtMost(max)
|
||||
|
||||
changed = true
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
onChange(RideBoostsUpdatePacket({ this }, getRideBoosts()))
|
||||
}
|
||||
}
|
||||
|
||||
fun setRideBoost(stat: RidingStat, boost: Float) {
|
||||
rideBoosts[stat] = boost.coerceIn(0F, getMaxRideBoost(stat))
|
||||
onChange(RideBoostsUpdatePacket({ this }, getRideBoosts()))
|
||||
onChange(RideBoostsUpdatePacket({ this }, rideBoosts))
|
||||
}
|
||||
|
||||
fun setRideBoosts(boosts: Map<RidingStat, Float>) {
|
||||
rideBoosts.clear()
|
||||
rideBoosts.putAll(boosts.mapValues { it.value.coerceIn(0F, getMaxRideBoost(it.key)) })
|
||||
onChange(RideBoostsUpdatePacket({ this }, getRideBoosts()))
|
||||
onChange(RideBoostsUpdatePacket({ this }, rideBoosts))
|
||||
}
|
||||
|
||||
fun getExperienceToNextLevel() = getExperienceToLevel(level + 1)
|
||||
|
||||
@@ -14,11 +14,10 @@ import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
class BlockBehavior {
|
||||
private val immuneToSweetBerryBushBlock = false
|
||||
private val canStandOnPowderSnow = false
|
||||
val canPathThroughSaccLeaves = false
|
||||
|
||||
@Transient
|
||||
val struct = ObjectValue(this).also {
|
||||
it.addFunction("immune_to_sweet_berry_bush_block") { DoubleValue(immuneToSweetBerryBushBlock) }
|
||||
it.addFunction("can_stand_on_powder_snow") { DoubleValue(canStandOnPowderSnow) }
|
||||
it.addFunction("can_path_through_sacc_leaves") { DoubleValue(canPathThroughSaccLeaves) }
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
|
||||
class CombatBehaviour {
|
||||
var willDefendSelf = true
|
||||
var willDefendSelf = false
|
||||
var willFlee = true
|
||||
var willDefendOwner = false
|
||||
var fightsMelee = true
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.ai
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.entity.OmniPathingEntity
|
||||
import com.cobblemon.mod.common.util.canFit
|
||||
import com.google.common.collect.Maps
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
|
||||
import java.util.EnumSet
|
||||
import java.util.function.Predicate
|
||||
import kotlin.math.max
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.tags.BlockTags
|
||||
@@ -27,14 +29,15 @@ import net.minecraft.world.level.block.BaseRailBlock
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.FenceGateBlock
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.pathfinder.*
|
||||
import net.minecraft.world.level.pathfinder.Node
|
||||
import net.minecraft.world.level.pathfinder.NodeEvaluator
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.level.pathfinder.PathfindingContext
|
||||
import net.minecraft.world.level.pathfinder.Target
|
||||
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.*
|
||||
import java.util.function.Predicate
|
||||
import kotlin.math.max
|
||||
|
||||
|
||||
/**
|
||||
* A path node maker that constructs paths knowing that the entity might be capable of
|
||||
@@ -85,7 +88,6 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
Long2ObjectFunction<PathType?> { this.getPathTypeOfMob(currentContext, x, y, z, entity) }
|
||||
)
|
||||
}
|
||||
|
||||
fun doesBlockHavePartialCollision(pathType: PathType): Boolean {
|
||||
return pathType == PathType.FENCE || pathType == PathType.DOOR_WOOD_CLOSED || pathType == PathType.DOOR_IRON_CLOSED
|
||||
}
|
||||
@@ -94,15 +96,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
return max(1.125, mob.maxUpStep().toDouble())
|
||||
}
|
||||
|
||||
protected fun findAcceptedNodeWalk(
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
verticalDeltaLimit: Int,
|
||||
nodeFloorLevel: Double,
|
||||
direction: Direction?,
|
||||
pathType: PathType?
|
||||
): Node? {
|
||||
protected fun findAcceptedNodeWalk(x: Int, y: Int, z: Int, verticalDeltaLimit: Int, nodeFloorLevel: Double, direction: Direction?, pathType: PathType?): Node? {
|
||||
var node: Node? = null
|
||||
val mutableBlockPos = BlockPos.MutableBlockPos()
|
||||
val d: Double = this.getFloorLevel(mutableBlockPos.set(x, y, z))
|
||||
@@ -119,23 +113,12 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
if (f >= 0.0f) {
|
||||
node = this.getNodeAndUpdateCostToMax(x, y, z, pathType2, f)
|
||||
}
|
||||
if (pathType?.let { doesBlockHavePartialCollision(it) } == true && node != null && node.costMalus >= 0.0f && !this.canReachWithoutCollision(
|
||||
node
|
||||
)) {
|
||||
if ( pathType?.let { doesBlockHavePartialCollision(it) } == true && node != null && node.costMalus >= 0.0f && !this.canReachWithoutCollision(node)) {
|
||||
node = null
|
||||
}
|
||||
if (pathType2 != PathType.WALKABLE) {
|
||||
if (pathType2 != PathType.WALKABLE ) {
|
||||
if ((node == null || node.costMalus < 0.0f) && verticalDeltaLimit > 0 && (pathType2 != PathType.FENCE || canWalkOverFences()) && pathType2 != PathType.UNPASSABLE_RAIL && pathType2 != PathType.TRAPDOOR && pathType2 != PathType.POWDER_SNOW) {
|
||||
node = this.tryJumpOn(
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
verticalDeltaLimit,
|
||||
nodeFloorLevel,
|
||||
direction!!,
|
||||
pathType!!,
|
||||
mutableBlockPos
|
||||
)
|
||||
node = this.tryJumpOn(x, y, z, verticalDeltaLimit, nodeFloorLevel, direction!!, pathType!!, mutableBlockPos)
|
||||
} else if (pathType2 == PathType.WATER && !canFloat()) {
|
||||
node = this.tryFindFirstNonWaterBelow(x, y, z, node)
|
||||
} else if (pathType2 == PathType.OPEN) {
|
||||
@@ -160,11 +143,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
|
||||
private fun canReachWithoutCollision(node: Node): Boolean {
|
||||
var aABB = mob.boundingBox
|
||||
var vec3 = Vec3(
|
||||
node.x.toDouble() - mob.x + aABB.xsize / 2.0,
|
||||
node.y.toDouble() - mob.y + aABB.ysize / 2.0,
|
||||
node.z.toDouble() - mob.z + aABB.zsize / 2.0
|
||||
)
|
||||
var vec3 = Vec3(node.x.toDouble() - mob.x + aABB.xsize / 2.0, node.y.toDouble() - mob.y + aABB.ysize / 2.0, node.z.toDouble() - mob.z + aABB.zsize / 2.0)
|
||||
val i = Mth.ceil(vec3.length() / aABB.size)
|
||||
vec3 = vec3.scale((1.0f / i.toFloat()).toDouble())
|
||||
for (j in 1..i) {
|
||||
@@ -208,22 +187,13 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
}
|
||||
|
||||
private fun getNodeAndUpdateCostToMax(x: Int, y: Int, z: Int, pathType: PathType, malus: Float): Node? {
|
||||
val node = this.getNode(x, y, z) ?: super.getNode(x, y, z) ?: return null
|
||||
val node = this.getNode(x, y, z) ?: super.getNode(x,y,z) ?: return null
|
||||
node.type = pathType
|
||||
node.costMalus = max(node.costMalus.toDouble(), malus.toDouble()).toFloat()
|
||||
return node
|
||||
}
|
||||
|
||||
private fun tryJumpOn(
|
||||
x: Int,
|
||||
y: Int,
|
||||
z: Int,
|
||||
verticalDeltaLimit: Int,
|
||||
nodeFloorLevel: Double,
|
||||
direction: Direction,
|
||||
pathType: PathType,
|
||||
pos: BlockPos.MutableBlockPos
|
||||
): Node? {
|
||||
private fun tryJumpOn(x: Int, y: Int, z: Int, verticalDeltaLimit: Int, nodeFloorLevel: Double, direction: Direction, pathType: PathType, pos: BlockPos.MutableBlockPos): Node? {
|
||||
val node = findAcceptedNodeWalk(x, y + 1, z, verticalDeltaLimit - 1, nodeFloorLevel, direction, pathType)
|
||||
return if (node == null) {
|
||||
null
|
||||
@@ -235,20 +205,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
val d = (x - direction.stepX).toDouble() + 0.5
|
||||
val e = (z - direction.stepZ).toDouble() + 0.5
|
||||
val f = mob.bbWidth.toDouble() / 2.0
|
||||
val aABB = AABB(
|
||||
d - f,
|
||||
this.getFloorLevel(pos.set(d, (y + 1).toDouble(), e)) + 0.001,
|
||||
e - f,
|
||||
d + f,
|
||||
mob.bbHeight.toDouble() + this.getFloorLevel(
|
||||
pos.set(
|
||||
node.x.toDouble(),
|
||||
node.y.toDouble(),
|
||||
node.z.toDouble()
|
||||
)
|
||||
) - 0.002,
|
||||
e + f
|
||||
)
|
||||
val aABB = AABB(d - f, this.getFloorLevel(pos.set(d, (y + 1).toDouble(), e)) + 0.001, e - f, d + f, mob.bbHeight.toDouble() + this.getFloorLevel(pos.set(node.x.toDouble(), node.y.toDouble(), node.z.toDouble())) - 0.002, e + f)
|
||||
if (this.hasCollisions(aABB)) null else node
|
||||
}
|
||||
}
|
||||
@@ -270,9 +227,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
if ((canFloat()) && blockGetter.getFluidState(pos).`is`(FluidTags.WATER)) {
|
||||
return pos.y.toDouble() + 0.5
|
||||
}
|
||||
return if ((canFloat()) && blockGetter.getFluidState(pos)
|
||||
.`is`(FluidTags.WATER)
|
||||
) pos.y.toDouble() + 0.5 else WalkNodeEvaluator.getFloorLevel(blockGetter, pos)
|
||||
return if ((canFloat()) && blockGetter.getFluidState(pos).`is`(FluidTags.WATER)) pos.y.toDouble() + 0.5 else WalkNodeEvaluator.getFloorLevel(blockGetter, pos)
|
||||
}
|
||||
|
||||
override fun getNeighbors(successors: Array<Node?>, node: Node): Int {
|
||||
@@ -286,20 +241,11 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
|
||||
// Non-diagonal surroundings in 3d space
|
||||
for (direction in Direction.entries) {
|
||||
var pathNode: Node?
|
||||
var pathNode : Node?
|
||||
if (mob.isInWater || canFly()) {
|
||||
pathNode = this.getNode(node.x + direction.stepX, node.y + direction.stepY, node.z + direction.stepZ)
|
||||
?: continue
|
||||
pathNode = this.getNode(node.x + direction.stepX, node.y + direction.stepY, node.z + direction.stepZ) ?: continue
|
||||
} else {
|
||||
pathNode = findAcceptedNodeWalk(
|
||||
node.x + direction.stepX,
|
||||
node.y + direction.stepY,
|
||||
node.z + direction.stepZ,
|
||||
if (direction == Direction.DOWN || direction == Direction.UP) 0 else 1,
|
||||
d,
|
||||
direction,
|
||||
node.type
|
||||
) ?: continue
|
||||
pathNode = findAcceptedNodeWalk(node.x + direction.stepX, node.y + direction.stepY, node.z + direction.stepZ, if (direction == Direction.DOWN || direction == Direction.UP) 0 else 1, d, direction, node.type) ?: continue
|
||||
}
|
||||
map[direction] = pathNode
|
||||
if (!hasNotVisited(pathNode, node)) {
|
||||
@@ -313,34 +259,21 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
val direction2 = direction.clockWise
|
||||
val x = node.x + direction.stepX + direction2.stepX
|
||||
val z = node.z + direction.stepZ + direction2.stepZ
|
||||
var pathNode2: Node?
|
||||
var pathNode2 : Node?
|
||||
if (mob.isInWater || canFly()) {
|
||||
pathNode2 = this.getNode(x, node.y, z) ?: continue
|
||||
} else {
|
||||
pathNode2 = findAcceptedNodeWalk(
|
||||
x,
|
||||
node.y,
|
||||
z,
|
||||
if (direction == Direction.DOWN || direction == Direction.UP) 0 else 1,
|
||||
d,
|
||||
direction,
|
||||
node.type
|
||||
) ?: continue
|
||||
pathNode2 = findAcceptedNodeWalk(x, node.y, z, if (direction == Direction.DOWN || direction == Direction.UP) 0 else 1, d, direction, node.type) ?: continue
|
||||
}
|
||||
// Skip 'inaccessible' diagonals if we're pathing from a blocked node since we're trying to get unstuck
|
||||
if (isAccessibleDiagonal(
|
||||
pathNode2,
|
||||
map[direction],
|
||||
map[direction2]
|
||||
) || (node.type == PathType.BLOCKED && !pathNode2.closed)
|
||||
) {
|
||||
if (isAccessibleDiagonal(pathNode2, map[direction], map[direction2]) || (node.type == PathType.BLOCKED && !pathNode2.closed)) {
|
||||
successors[i++] = pathNode2
|
||||
}
|
||||
}
|
||||
if (canFly() || mob.isInWater) {
|
||||
// Upward non-diagonals
|
||||
for (direction in Direction.Plane.HORIZONTAL.iterator()) {
|
||||
var pathNode2: Node? = null
|
||||
var pathNode2 : Node? = null
|
||||
pathNode2 = getNode(node.x + direction.stepX, node.y + 1, node.z + direction.stepZ) ?: continue
|
||||
|
||||
if (upIsOpen && hasNotVisited(pathNode2, node)) {
|
||||
@@ -352,12 +285,8 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
// Upward diagonals
|
||||
for (direction in Direction.Plane.HORIZONTAL.iterator()) {
|
||||
val direction2 = direction.clockWise
|
||||
var pathNode2: Node? = null
|
||||
pathNode2 = getNode(
|
||||
node.x + direction.stepX + direction2.stepX,
|
||||
node.y + 1,
|
||||
node.z + direction.stepZ + direction2.stepZ
|
||||
) ?: continue
|
||||
var pathNode2 : Node? = null
|
||||
pathNode2 = getNode(node.x + direction.stepX + direction2.stepX, node.y + 1, node.z + direction.stepZ + direction2.stepZ) ?: continue
|
||||
|
||||
if (isAccessibleDiagonal(pathNode2, upperMap[direction], upperMap[direction2])) {
|
||||
successors[i++] = pathNode2
|
||||
@@ -380,11 +309,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
// Downward diagonals
|
||||
for (direction in Direction.Plane.HORIZONTAL.iterator()) {
|
||||
val direction2 = direction.clockWise
|
||||
val pathNode2 = getNode(
|
||||
node.x + direction.stepX + direction2.stepX,
|
||||
node.y - 1,
|
||||
node.z + direction.stepZ + direction2.stepZ
|
||||
) ?: continue
|
||||
val pathNode2 = getNode(node.x + direction.stepX + direction2.stepX, node.y - 1, node.z + direction.stepZ + direction2.stepZ) ?: continue
|
||||
if (isAccessibleDiagonal(pathNode2, lowerMap[direction], lowerMap[direction2])) {
|
||||
successors[i++] = pathNode2
|
||||
}
|
||||
@@ -427,12 +352,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
}
|
||||
|
||||
fun isAccessibleDiagonal(pathNode: Node, vararg borderNodes: Node?): Boolean {
|
||||
return borderNodes.all {
|
||||
it != null && hasNotVisited(
|
||||
pathNode,
|
||||
it
|
||||
)
|
||||
} && borderNodes.all { it != null && it.costMalus >= 0.0F }
|
||||
return borderNodes.all{ it != null && hasNotVisited(pathNode, it) } && borderNodes.all { it != null && it.costMalus >= 0.0F }
|
||||
}
|
||||
|
||||
fun isValidPathType(type: PathType): Boolean {
|
||||
@@ -465,9 +385,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
}
|
||||
|
||||
fun addNodePos(x: Int, y: Int, z: Int): PathType {
|
||||
return nodePosToType.computeIfAbsent(
|
||||
BlockPos.asLong(x, y, z),
|
||||
Long2ObjectFunction { getPathTypeOfMob(currentContext, x, y, z, mob) })
|
||||
return nodePosToType.computeIfAbsent(BlockPos.asLong(x, y, z), Long2ObjectFunction { getPathTypeOfMob(currentContext, x, y, z, mob) })
|
||||
}
|
||||
|
||||
override fun getPathType(pfContext: PathfindingContext, x: Int, y: Int, z: Int): PathType {
|
||||
@@ -493,7 +411,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
var figuredNode = if (blockState.`is`(BlockTags.FENCES) || blockState.`is`(BlockTags.WALLS)) {
|
||||
PathType.FENCE
|
||||
} else if (blockStateBelow.block is FenceGateBlock) {
|
||||
if (blockStateBelow.getValue(FenceGateBlock.OPEN)) {
|
||||
if(blockStateBelow.getValue(FenceGateBlock.OPEN)) {
|
||||
PathType.OPEN
|
||||
} else {
|
||||
PathType.FENCE
|
||||
@@ -522,8 +440,6 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
// PathType.WALKABLE
|
||||
// } else if (blockState.canPathfindThrough(world, pos, NavigationType.AIR) && !blockStateBelow.isSideSolid(world, below, Direction.UP, SideShapeType.FULL)) {
|
||||
// PathType.OPEN
|
||||
} else if (blockState.`is`(BlockTags.LEAVES) && blockState.block == CobblemonBlocks.SACCHARINE_LEAVES && canPathThroughLeaves()) {
|
||||
return PathType.OPEN
|
||||
} else PathType.BLOCKED
|
||||
|
||||
if (figuredNode == PathType.OPEN && pos.y >= pfContext.level().getMinBuildHeight() + 1) {
|
||||
@@ -554,15 +470,10 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
val sizeX = (mob.boundingBox.maxX - mob.boundingBox.minX).toInt() + 1
|
||||
val sizeY = (mob.boundingBox.maxY - mob.boundingBox.minY).toInt() + 1
|
||||
val sizeZ = (mob.boundingBox.maxZ - mob.boundingBox.minZ).toInt() + 1
|
||||
val type = findNearbyNodeTypes(
|
||||
pfContext, x, y, z, sizeX, sizeY, sizeZ, canOpenDoors, canPassDoors, set, PathType.BLOCKED,
|
||||
val type = findNearbyNodeTypes(pfContext, x, y, z, sizeX, sizeY, sizeZ, canOpenDoors, canPassDoors, set, PathType.BLOCKED,
|
||||
BlockPos(x, y, z)
|
||||
)
|
||||
|
||||
if (PathType.LEAVES in set) {
|
||||
return PathType.OPEN
|
||||
}
|
||||
|
||||
if (PathType.FENCE in set) {
|
||||
return PathType.FENCE
|
||||
}
|
||||
@@ -663,11 +574,7 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
} else if (type == PathType.RAIL && block !is BaseRailBlock && pfContext.getBlockState(pos.below()).block !is BaseRailBlock) {
|
||||
PathType.UNPASSABLE_RAIL
|
||||
} else if (type == PathType.LEAVES) {
|
||||
if (blockState.block === CobblemonBlocks.SACCHARINE_LEAVES && canPathThroughLeaves()) {
|
||||
PathType.OPEN
|
||||
} else {
|
||||
PathType.BLOCKED
|
||||
}
|
||||
PathType.BLOCKED
|
||||
} else type
|
||||
}
|
||||
|
||||
@@ -687,13 +594,13 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
}
|
||||
}
|
||||
|
||||
fun canSwimInWater(): Boolean {
|
||||
return if (this.mob is OmniPathingEntity) {
|
||||
(this.mob as OmniPathingEntity).canSwimInWater()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fun canSwimInWater(): Boolean {
|
||||
return if (this.mob is OmniPathingEntity) {
|
||||
(this.mob as OmniPathingEntity).canSwimInWater()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun canSwimUnderFluid(fluidState: FluidState): Boolean {
|
||||
return if (this.mob is OmniPathingEntity) {
|
||||
@@ -703,14 +610,6 @@ class OmniPathNodeMaker : NodeEvaluator() {
|
||||
}
|
||||
}
|
||||
|
||||
fun canPathThroughLeaves() : Boolean {
|
||||
return if (this.mob is OmniPathingEntity) {
|
||||
(this.mob as OmniPathingEntity).canPathThroughSaccLeaves()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun canWalkOnWater(): Boolean {
|
||||
return if (this.mob is OmniPathingEntity) {
|
||||
(this.mob as OmniPathingEntity).canWalkOnWater()
|
||||
|
||||
@@ -195,8 +195,8 @@ object PokemonBrain {
|
||||
CobblemonMemories.RECENTLY_ATE_GRASS,
|
||||
CobblemonMemories.HIVE_LOCATION,
|
||||
CobblemonMemories.HIVE_COOLDOWN,
|
||||
CobblemonMemories.NEARBY_FLOWER,
|
||||
CobblemonMemories.HAS_NECTAR,
|
||||
CobblemonMemories.NEARBY_FLOWERS,
|
||||
CobblemonMemories.POLLINATED,
|
||||
CobblemonMemories.RECENTLY_ATE_GRASS,
|
||||
CobblemonMemories.HERD_LEADER,
|
||||
CobblemonMemories.HERD_SIZE,
|
||||
|
||||
+45
-49
@@ -100,57 +100,53 @@ object CobblemonHeldItemManager : BaseCobblemonHeldItemManager() {
|
||||
return this.showdownIdOf(itemStack.item)
|
||||
}
|
||||
|
||||
override fun handleStartInstruction(pokemon: BattlePokemon, battle: PokemonBattle, battleMessage: BattleMessage) {
|
||||
val itemID = battleMessage.effectAt(1)?.id ?: return
|
||||
val consumeHeldItems = this.shouldConsumeItem(pokemon, battle, itemID)
|
||||
if (battleMessage.hasOptionalArgument("silent")) {
|
||||
if (consumeHeldItems) {
|
||||
this.take(pokemon, itemID)
|
||||
override fun handleStartInstruction(pokemon: BattlePokemon, battle: PokemonBattle, battleMessage: BattleMessage) {
|
||||
val itemID = battleMessage.effectAt(1)?.id ?: return
|
||||
val consumeHeldItems = this.shouldConsumeItem(pokemon, battle, itemID)
|
||||
if (battleMessage.hasOptionalArgument("silent")) {
|
||||
if (consumeHeldItems) {
|
||||
this.take(pokemon, itemID)
|
||||
}
|
||||
return
|
||||
}
|
||||
val effect = battleMessage.effect()
|
||||
val battlerName = pokemon.getName()
|
||||
val itemName = this.nameOf(itemID)
|
||||
// Airballoon is the only item using the null effect gimmick
|
||||
if (effect == null) {
|
||||
battle.broadcastChatMessage(battleLang("item.$itemID", battlerName, itemName))
|
||||
return
|
||||
}
|
||||
val sourceName = battleMessage.battlePokemonFromOptional(battle)?.getName() ?: Component.literal("UNKNOWN")
|
||||
val effectId = effect.id
|
||||
val text = when (effectId) {
|
||||
"magician", "pickpocket", "covet", "thief" -> battleLang("item.thief", battlerName, itemName, sourceName) // The "source" is actually the target here
|
||||
"pickup", "recycle" -> battleLang("item.recycle", battlerName, itemName)
|
||||
"switcheroo", "trick" -> battleLang("item.trick", battlerName, itemName)
|
||||
else -> battleLang("item.$effectId", battlerName, itemName, sourceName)
|
||||
}
|
||||
battle.broadcastChatMessage(text)
|
||||
// If it's a take and give effect, we don't want to follow through if we are not consuming held items
|
||||
if (this.takeItemEffect.contains(effectId) && this.giveItemEffect.contains(effectId) && !consumeHeldItems) {
|
||||
return
|
||||
}
|
||||
// Block item swapping in PVP until we have a rule
|
||||
if (battle.isPvP && !consumeHeldItems) {
|
||||
return
|
||||
}
|
||||
// Block stealing from NPCs
|
||||
if (battle.isPvN) {
|
||||
return
|
||||
}
|
||||
// if items aren't consumed, then we don't want to give them to wild pokemon (dupe)
|
||||
if (this.giveItemEffect.contains(effectId) && (pokemon.actor is PlayerBattleActor || consumeHeldItems)) {
|
||||
this.give(pokemon, itemID)
|
||||
}
|
||||
// allow players to steal wild held items
|
||||
if (this.takeItemEffect.contains(effectId) && (pokemon.actor !is PlayerBattleActor || consumeHeldItems)) {
|
||||
battleMessage.actorAndActivePokemonFromOptional(battle)?.second?.battlePokemon?.let { this.take(it, itemID) }
|
||||
}
|
||||
return
|
||||
}
|
||||
val effect = battleMessage.effect()
|
||||
val battlerName = pokemon.getName()
|
||||
val itemName = this.nameOf(itemID)
|
||||
// Airballoon is the only item using the null effect gimmick
|
||||
if (effect == null) {
|
||||
battle.broadcastChatMessage(battleLang("item.$itemID", battlerName, itemName))
|
||||
return
|
||||
}
|
||||
val sourceName = battleMessage.battlePokemonFromOptional(battle)?.getName() ?: Component.literal("UNKNOWN")
|
||||
val effectId = effect.id
|
||||
val text = when (effectId) {
|
||||
"magician", "pickpocket", "covet", "thief" -> battleLang("item.thief", battlerName, itemName, sourceName) // The "source" is actually the target here
|
||||
"pickup", "recycle" -> battleLang("item.recycle", battlerName, itemName)
|
||||
"switcheroo", "trick" -> battleLang("item.trick", battlerName, itemName)
|
||||
else -> battleLang("item.$effectId", battlerName, itemName, sourceName)
|
||||
}
|
||||
battle.broadcastChatMessage(text)
|
||||
// If it's a take and give effect, we don't want to follow through if we are not consuming held items
|
||||
if (this.takeItemEffect.contains(effectId) && this.giveItemEffect.contains(effectId) && !consumeHeldItems) {
|
||||
return
|
||||
}
|
||||
// Prevent duping
|
||||
if (battle.isPvP && this.takeItemEffect.contains(effectId) || this.giveItemEffect.contains(effectId)) {
|
||||
return
|
||||
}
|
||||
// Block item swapping in PVP until we have a rule
|
||||
if (battle.isPvP && !consumeHeldItems) {
|
||||
return
|
||||
}
|
||||
// Block stealing from NPCs
|
||||
if (battle.isPvN) {
|
||||
return
|
||||
}
|
||||
// if items aren't consumed, then we don't want to give them to wild pokemon (dupe)
|
||||
if (this.giveItemEffect.contains(effectId) && (pokemon.actor is PlayerBattleActor || consumeHeldItems)) {
|
||||
this.give(pokemon, itemID)
|
||||
}
|
||||
// allow players to steal wild held items
|
||||
if (this.takeItemEffect.contains(effectId) && (pokemon.actor !is PlayerBattleActor || consumeHeldItems)) {
|
||||
battleMessage.actorAndActivePokemonFromOptional(battle)?.second?.battlePokemon?.let { this.take(it, itemID) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleEndInstruction(pokemon: BattlePokemon, battle: PokemonBattle, battleMessage: BattleMessage) {
|
||||
val itemID = battleMessage.effectAt(1)?.id ?: return
|
||||
|
||||
-1
@@ -50,7 +50,6 @@ object RidingBehaviourSettingsAdapter : JsonDeserializer<RidingBehaviourSettings
|
||||
MinekartBehaviour.KEY to MinekartSettings::class.java,
|
||||
HoverBehaviour.KEY to HoverSettings::class.java,
|
||||
RocketBehaviour.KEY to RocketSettings::class.java,
|
||||
SubmarineBehaviour.KEY to SubmarineSettings::class.java,
|
||||
CompositeBehaviour.KEY to CompositeSettings::class.java,
|
||||
|
||||
/*
|
||||
|
||||
+7
-8
@@ -21,7 +21,7 @@
|
||||
"per_update_expression": "variable.radius = 0.6;"
|
||||
},
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 60,
|
||||
"spawn_rate": 30,
|
||||
"max_particles": 10000
|
||||
},
|
||||
"minecraft:emitter_lifetime_expression": {
|
||||
@@ -29,14 +29,14 @@
|
||||
},
|
||||
"minecraft:emitter_shape_sphere": {
|
||||
"offset": [0, 0, -1],
|
||||
"radius": "0.85+(v.particle_random_4*1.25)",
|
||||
"radius": "1.25+(v.particle_random_4*1.25)",
|
||||
"surface_only": true,
|
||||
"direction": ["math.random(-0.1,0.1)*1", "math.random(-0.1,0.1)*1", "-math.random(-0.1,0.1)*1"]
|
||||
"direction": ["math.random(-0.1,0.1)*3", "math.random(-0.1,0.1)*1.25", "-0.5-math.random(-0.1,0.1)*2"]
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 1.25
|
||||
"max_lifetime": 1
|
||||
},
|
||||
"minecraft:particle_initial_speed": 0.3,
|
||||
"minecraft:particle_initial_speed": 1,
|
||||
"minecraft:particle_motion_dynamic": {
|
||||
"linear_drag_coefficient": "0.25+v.particle_random_4"
|
||||
},
|
||||
@@ -50,9 +50,8 @@
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [9, 9],
|
||||
"step_UV": [9, 0],
|
||||
"frames_per_second": 12,
|
||||
"max_frame": 11,
|
||||
"loop": true
|
||||
"frames_per_second": 20,
|
||||
"max_frame": 11
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+70
-310
@@ -87,9 +87,6 @@
|
||||
},
|
||||
"cannon_left": {
|
||||
"position": [0, 0, 3]
|
||||
},
|
||||
"locator_seat_water2": {
|
||||
"rotation": [32.5, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -553,9 +550,6 @@
|
||||
},
|
||||
"cannon_left": {
|
||||
"position": [0, 0, 3]
|
||||
},
|
||||
"locator_seat_water2": {
|
||||
"rotation": [35, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -708,12 +702,6 @@
|
||||
"cannon_left": {
|
||||
"position": [0, 0, 6.7],
|
||||
"scale": [1, 1, 0.9]
|
||||
},
|
||||
"locator_seat_water2": {
|
||||
"rotation": [-65, 0, 0]
|
||||
},
|
||||
"locator_seat_water": {
|
||||
"rotation": [-60, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -813,12 +801,6 @@
|
||||
"cannon_left": {
|
||||
"position": [0, 0, 7],
|
||||
"scale": 0
|
||||
},
|
||||
"locator_seat_water2": {
|
||||
"rotation": [-85, 0, 0]
|
||||
},
|
||||
"locator_seat_water": {
|
||||
"rotation": [-90, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -922,12 +904,6 @@
|
||||
"body": {
|
||||
"rotation": [9.93357, 0.75431, 0.939],
|
||||
"position": [0, -24.2, 0]
|
||||
},
|
||||
"locator_seat_water2": {
|
||||
"rotation": [-67.5, 0, 0]
|
||||
},
|
||||
"locator_seat_water": {
|
||||
"rotation": [-67.5, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1031,12 +1007,6 @@
|
||||
"body": {
|
||||
"rotation": [-2.5, 0, 0],
|
||||
"position": [0, -21, 0]
|
||||
},
|
||||
"locator_seat_water2": {
|
||||
"rotation": [-85, 0, 0]
|
||||
},
|
||||
"locator_seat_water": {
|
||||
"rotation": [-85, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1989,83 +1959,29 @@
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.5833": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.625": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.4583": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.5": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.7917": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.8333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
}
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"0.5833": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"0.625": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.0": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"1.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"1.4583": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"1.5": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.7917": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"1.8333": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.5833": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.625": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.4583": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.5": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.7917": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.8333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
}
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"0.5833": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"0.625": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.0": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"1.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"1.4583": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"1.5": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.7917": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"1.8333": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2325,67 +2241,25 @@
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.25": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.2917": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.625": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"0.25": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"0.2917": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.375": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"1.625": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"1.6667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.25": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.2917": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.625": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.6667": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"0.25": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"0.2917": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.375": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"1.4167": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"1.625": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"1.6667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3498,67 +3372,25 @@
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0833": [0, 0, 0],
|
||||
"0.125": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.7083": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.75": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0833": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.125": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"2.3333": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.125": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"0.7083": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"0.75": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"2.0833": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"2.125": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"2.2917": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"2.3333": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0833": [0, 0, 0],
|
||||
"0.125": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.7083": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.75": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0833": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.125": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"2.2917": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"2.3333": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.125": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"0.7083": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"0.75": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"2.0833": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"2.125": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"2.2917": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"2.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"foot_right": {
|
||||
@@ -4303,67 +4135,25 @@
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.375": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.2917": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.5": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.5417": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"0.3333": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"0.375": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"1.2917": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"1.5": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"1.5417": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.375": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.2917": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.5": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.5417": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.0417": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"0.3333": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"0.375": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"1.2917": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"1.5": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"1.5417": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"foot_right": {
|
||||
@@ -4940,35 +4730,17 @@
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.2917": [0, 0, 0],
|
||||
"0.3333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.1667": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"1.2083": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.3333": {"pre": [0, 0, 0], "post": [0.1, 0, -0.1]},
|
||||
"1.1667": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"1.2083": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.2917": [0, 0, 0],
|
||||
"0.3333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.1667": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"1.2083": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.3333": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"1.1667": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"1.2083": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5013,27 +4785,15 @@
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0.1, 0, -0.1],
|
||||
"0.25": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0.1, 0, -0.1]
|
||||
},
|
||||
"0.2917": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.25": {"pre": [0.1, 0, -0.1], "post": [0.1, 0, -0.1]},
|
||||
"0.2917": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [-0.1, 0, -0.1],
|
||||
"0.25": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [-0.1, 0, -0.1]
|
||||
},
|
||||
"0.2917": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
"0.25": {"pre": [-0.1, 0, -0.1], "post": [-0.1, 0, -0.1]},
|
||||
"0.2917": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+138
-150
@@ -163,7 +163,7 @@
|
||||
},
|
||||
"animation.exeggutor.ground_walk": {
|
||||
"loop": true,
|
||||
"animation_length": 4.7917,
|
||||
"animation_length": 4.79167,
|
||||
"bones": {
|
||||
"leg_left": {
|
||||
"rotation": {
|
||||
@@ -724,36 +724,126 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.exeggutor.cry": {
|
||||
"animation_length": 1.5,
|
||||
"bones": {
|
||||
"mouth": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [0, -2, 0],
|
||||
"1.25": [0, -2, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"mouth2": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [0, -5, 0],
|
||||
"1.25": [0, -5, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [0, -3, 0],
|
||||
"1.25": [0, -3, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [-15, 0, 0],
|
||||
"1.25": [-15, 0, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"mouth_closed": {
|
||||
"position": {
|
||||
"0.0": [0, 0, -0.1],
|
||||
"0.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]}
|
||||
}
|
||||
},
|
||||
"mouth_open": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
|
||||
}
|
||||
},
|
||||
"head2": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [-15, 0, 0],
|
||||
"1.25": [-15, 0, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"mouth_closed2": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.2]},
|
||||
"1.25": {"pre": [0, 0, 0.2], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"mouth_open2": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"1.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"head3": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [-15, 0, 0],
|
||||
"1.25": [-15, 0, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"mouth_closed3": {
|
||||
"position": {
|
||||
"0.0": [0, 0, -0.1],
|
||||
"0.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]}
|
||||
}
|
||||
},
|
||||
"mouth_open3": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.exeggutor.battle_idle": {
|
||||
"loop": true,
|
||||
"animation_length": 1.5833,
|
||||
"animation_length": 1.58333,
|
||||
"bones": {
|
||||
"leg_left": {
|
||||
"rotation": {
|
||||
"0.0": [-15, -35, 0],
|
||||
"0.0": ["-15+math.clamp(-math.sin(q.anim_time*90*2.5+225)*65,-90,0)", -35, 0],
|
||||
"0.5833": [-15, -35, 0],
|
||||
"0.7917": [-65, -35, 0],
|
||||
"0.9583": {
|
||||
"pre": [-75, -35, 0],
|
||||
"post": [-75, -35, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.125": {
|
||||
"post": [-65, -35, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.625": ["-15+math.clamp(-math.sin(q.anim_time*90*2.5+225)*65,-90,0)", -35, 0],
|
||||
"1.125": ["-15+math.clamp(-math.sin(q.anim_time*90*2.5+225)*65,-90,0)", -35, 0],
|
||||
"1.2917": [-15, -35, 0],
|
||||
"1.5833": [-15, -35, 0]
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0": [
|
||||
"math.clamp(math.sin(q.anim_time*90*2.5+225)*0.5,0,90)",
|
||||
"math.clamp(math.sin(q.anim_time*90*2.5+225)*3.5,0,90)",
|
||||
"math.clamp(-math.sin(q.anim_time*90*2.5+225)*2,-90,0)"
|
||||
],
|
||||
"0.5833": [0, 0, 0],
|
||||
"0.625": [0.06, 0.42, -0.24],
|
||||
"0.7083": [0.18, 1.26, -0.72],
|
||||
"0.7917": [0.15, 1.08, -0.62],
|
||||
"0.9167": [0.11, 0.81, -0.47],
|
||||
"1.0417": [0.07, 0.54, -0.31],
|
||||
"1.1667": [0.04, 0.27, -0.16],
|
||||
"0.625": [
|
||||
"math.clamp(math.sin(q.anim_time*90*2.5+225)*0.5,0,90)",
|
||||
"math.clamp(math.sin(q.anim_time*90*2.5+225)*3.5,0,90)",
|
||||
"math.clamp(-math.sin(q.anim_time*90*2.5+225)*2,-90,0)"
|
||||
],
|
||||
"1.2917": [0, 0, 0],
|
||||
"1.5833": [0, 0, 0]
|
||||
}
|
||||
@@ -762,7 +852,7 @@
|
||||
"rotation": {
|
||||
"0.0": [20, 0, 0],
|
||||
"0.5833": [20, 0, 0],
|
||||
"0.875": [40, 0, 0],
|
||||
"0.875": [5, 0, 0],
|
||||
"1.125": [20, 0, 0]
|
||||
}
|
||||
},
|
||||
@@ -770,55 +860,53 @@
|
||||
"rotation": {
|
||||
"0.0": [-5, 0, 0],
|
||||
"0.5833": [-5, 0, 0],
|
||||
"0.7083": [17.5, 0, 0],
|
||||
"0.9167": [-5, 0, 0]
|
||||
"0.7083": [30, 0, 0],
|
||||
"0.9167": [10, 0, 0],
|
||||
"1.125": [-5, 0, 0],
|
||||
"1.25": [-5, 0, 0]
|
||||
}
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": {
|
||||
"0.0": [-65, 35, 0],
|
||||
"0.1667": {
|
||||
"pre": [-75, 35, 0],
|
||||
"post": [-75, 35, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.3333": {
|
||||
"post": [-65, 35, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.0": ["-15+math.clamp(math.sin(q.anim_time*90*2.5+225)*65,-90,0)", 35, 0],
|
||||
"0.3333": ["-15+math.clamp(math.sin(q.anim_time*90*2.5+225)*65,-90,0)", 35, 0],
|
||||
"0.5": [-15, 35, 0],
|
||||
"1.3333": [-15, 35, 0],
|
||||
"1.375": [-15, 35, 0],
|
||||
"1.5833": [-65, 35, 0]
|
||||
"1.375": ["-15+math.clamp(math.sin(q.anim_time*90*2.5+225)*65,-90,0)", 35, 0]
|
||||
},
|
||||
"position": {
|
||||
"0.0": [-0.37, 2.61, -1.49],
|
||||
"0.0417": [-0.37, 2.61, -1.49],
|
||||
"0.125": [-0.3, 2.13, -1.22],
|
||||
"0.25": [-0.2, 1.42, -0.81],
|
||||
"0.375": [-0.1, 0.71, -0.4],
|
||||
"0.0": [
|
||||
"math.clamp(math.sin(q.anim_time*90*2.5+225)*0.5,-90,0)",
|
||||
"math.clamp(-math.sin(q.anim_time*90*2.5+225)*3.5,0,90)",
|
||||
"math.clamp(math.sin(q.anim_time*90*2.5+225)*2,-90,0)"
|
||||
],
|
||||
"0.5": [0, 0, 0],
|
||||
"1.3333": [0, 0, 0],
|
||||
"1.375": [0, 0, 0],
|
||||
"1.5833": [-0.37, 2.61, -1.49]
|
||||
"1.375": [
|
||||
"math.clamp(math.sin(q.anim_time*90*2.5+225)*0.5,-90,0)",
|
||||
"math.clamp(-math.sin(q.anim_time*90*2.5+225)*3.5,0,90)",
|
||||
"math.clamp(math.sin(q.anim_time*90*2.5+225)*2,-90,0)"
|
||||
]
|
||||
}
|
||||
},
|
||||
"leg_right2": {
|
||||
"rotation": {
|
||||
"0.0": [35, 0, 0],
|
||||
"0.125": [40, 0, 0],
|
||||
"0.0": [7, 0, 0],
|
||||
"0.125": [5, 0, 0],
|
||||
"0.375": [20, 0, 0],
|
||||
"1.375": [20, 0, 0],
|
||||
"1.5833": [35, 0, 0]
|
||||
"1.5833": [7, 0, 0]
|
||||
}
|
||||
},
|
||||
"foot_right": {
|
||||
"rotation": {
|
||||
"0.0": [4, 0, 0],
|
||||
"0.0833": [-5, 0, 0],
|
||||
"0.0": [22, 0, 0],
|
||||
"0.125": [10, 0, 0],
|
||||
"0.3333": [-5, 0, 0],
|
||||
"0.4583": [-5, 0, 0],
|
||||
"1.375": [-5, 0, 0],
|
||||
"1.5": [17.5, 0, 0],
|
||||
"1.5833": [8.5, 0, 0]
|
||||
"1.5": [30, 0, 0],
|
||||
"1.5833": [22, 0, 0]
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
@@ -975,106 +1063,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.exeggutor.cry": {
|
||||
"animation_length": 1.5,
|
||||
"bones": {
|
||||
"mouth": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [0, -2, 0],
|
||||
"1.25": [0, -2, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"mouth2": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [0, -5, 0],
|
||||
"1.25": [0, -5, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [0, -3, 0],
|
||||
"1.25": [0, -3, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [-5, 0, 0],
|
||||
"1.25": [-2.5, 0, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"mouth_closed": {
|
||||
"position": {
|
||||
"0.0": [-1, 0, -0.1],
|
||||
"0.25": {"pre": [-1, 0, -0.1], "post": [-1, 0, 0]},
|
||||
"1.25": {"pre": [-1, 0, 0], "post": [-1, 0, -0.1]}
|
||||
}
|
||||
},
|
||||
"mouth_open": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
|
||||
}
|
||||
},
|
||||
"head2": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [-5, 0, 0],
|
||||
"1.25": [-2.5, 0, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"mouth_closed2": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.2]},
|
||||
"1.25": {"pre": [0, 0, 0.2], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"mouth_open2": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"1.25": {"pre": [0, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"head3": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": [-5, 0, 0],
|
||||
"1.25": [-2.5, 0, 0],
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"mouth_closed3": {
|
||||
"position": {
|
||||
"0.0": [-1, 0, -0.1],
|
||||
"0.25": {"pre": [-1, 0, -0.1], "post": [-1, 0, 0]},
|
||||
"1.25": {"pre": [-1, 0, 0], "post": [-1, 0, -0.1]}
|
||||
}
|
||||
},
|
||||
"mouth_open3": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.25": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.25": {
|
||||
"effect": "pokemon.exeggutor.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.exeggutor.sleep": {
|
||||
"loop": true,
|
||||
"animation_length": 8,
|
||||
@@ -1306,7 +1294,7 @@
|
||||
}
|
||||
},
|
||||
"animation.exeggutor.blink3": {
|
||||
"animation_length": 0.1667,
|
||||
"animation_length": 0.16667,
|
||||
"bones": {
|
||||
"eyelid_right3": {
|
||||
"position": {
|
||||
|
||||
+369
-1845
File diff suppressed because it is too large
Load Diff
+76
-582
@@ -5,78 +5,47 @@
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": ["-5+math.cos(query.anim_time*90*1)*2", 0, "0+math.cos(query.anim_time*90*1/2)*2"],
|
||||
"position": ["0+math.sin(query.anim_time*90*1/2)*0.75", "3+math.sin(query.anim_time*90*1)*0.5", 0]
|
||||
"rotation": ["5+(math.sin(q.anim_time*90*2*1+180)*6)*0.6", 0, "0+(math.sin(q.anim_time*90*2*1+180)*1)*0.6"],
|
||||
"position": [0, "2+(math.cos(q.anim_time*90*2*1+180)*0.8)*0.6", 0]
|
||||
},
|
||||
"torso_top": {
|
||||
"rotation": ["2.5-math.cos(query.anim_time*90*1-30)*2", 0, "0+math.cos(query.anim_time*90*1/2-60)*2"]
|
||||
"rotation": ["0-(math.sin(q.anim_time*90*2*1+180)*1.5)*0.6", 0, 0]
|
||||
},
|
||||
"collar_back": {
|
||||
"rotation": ["0+math.cos(query.anim_time*90*1-30)*2", 0, 0]
|
||||
"rotation": ["0-(math.sin(q.anim_time*90*2*1+180)*5)*0.6", 0, 0]
|
||||
},
|
||||
"collar_front": {
|
||||
"rotation": ["27.5-math.cos(query.anim_time*90*1-60)*1", 0, 0]
|
||||
},
|
||||
"eyes_bright": {
|
||||
"position": [0, 0, -0.1]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [
|
||||
"26.4641+math.cos(query.anim_time*90*1/2-120)*7",
|
||||
"19.3475-math.cos(query.anim_time*90*1/2-60)*6",
|
||||
"-42.5248-math.cos(query.anim_time*90*1-90)*2"
|
||||
]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [
|
||||
"48.1034+math.cos(query.anim_time*90*1-90)*6",
|
||||
"-28.22+math.cos(query.anim_time*90*1/2-90)*8",
|
||||
"-9.9783-math.cos(query.anim_time*90*1-120)*6"
|
||||
]
|
||||
},
|
||||
"hand_right": {
|
||||
"rotation": [12.42995, "-10.0859-math.cos(query.anim_time*90*1-120)*5", "-31.3315+math.cos(query.anim_time*90*1-150)*6"]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [
|
||||
"26.4641+math.cos(query.anim_time*90*1/2-120)*7",
|
||||
"-19.3475+math.cos(query.anim_time*90*1/2-60)*6",
|
||||
"42.5248+math.cos(query.anim_time*90*1-90)*2"
|
||||
]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [
|
||||
"48.1034+math.cos(query.anim_time*90*1-90)*6",
|
||||
"28.22-math.cos(query.anim_time*90*1/2-90)*8",
|
||||
"9.9783+math.cos(query.anim_time*90*1-120)*6"
|
||||
]
|
||||
},
|
||||
"hand_left": {
|
||||
"rotation": [12.42995, "10.0859+math.cos(query.anim_time*90*1-120)*5", "31.3315-math.cos(query.anim_time*90*1-150)*6"]
|
||||
},
|
||||
"torso_bottom": {
|
||||
"rotation": ["-7.5+math.cos(query.anim_time*90*1-60)*2", 0, "0-math.cos(query.anim_time*90*1/2-120)*2"]
|
||||
},
|
||||
"bottom_coat": {
|
||||
"rotation": ["-3+math.cos(query.anim_time*90*1-90)*2", 0, "0-math.cos(query.anim_time*90*1/2-90)*3"]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": ["2.5062+math.cos(query.anim_time*90*1-120)*6", 10.02087, "2.4142-math.cos(query.anim_time*90*1/2-90)*8"]
|
||||
},
|
||||
"leg_right2": {
|
||||
"rotation": ["22.5+math.cos(query.anim_time*90*1-170)*10", 0, "NaN-math.cos(query.anim_time*90*1/2-150)*6"]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": ["2.5062+math.cos(query.anim_time*90*1-120)*6", -10.02087, "-2.4142-math.cos(query.anim_time*90*1/2-90)*8"]
|
||||
},
|
||||
"leg_left2": {
|
||||
"rotation": ["22.5+math.cos(query.anim_time*90*1-170)*10", 0, "-math.cos(query.anim_time*90*1/2-150)*6"]
|
||||
},
|
||||
"eyes_dim": {
|
||||
"position": [0, 0, 0.1]
|
||||
"rotation": ["0+(math.sin(q.anim_time*90*2*1+180)*5)*0.6", 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["15+math.cos(query.anim_time*90*1)*1", 0, "0-math.cos(query.anim_time*90*1/2-120)*3"]
|
||||
"rotation": ["5-(math.sin(q.anim_time*90*2*1+180)*3)*0.6", 0, 0]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [0, "(math.sin(q.anim_time*90*2*1+180)*2)*1", "-60-(math.sin(q.anim_time*90*2*1+180)*2)*0.6"]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [0, "0+(math.cos(q.anim_time*90*2*1+180)*1)*0.6", 0]
|
||||
},
|
||||
"hand_right": {
|
||||
"rotation": [0, 0, -10]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [0, "-(math.sin(q.anim_time*90*2*1+180)*2)*1", "60+(math.sin(q.anim_time*90*2*1+180)*2)*0.6"]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [0, "0-(math.sin(q.anim_time*90*2*1+180)*5)*0.6", 0]
|
||||
},
|
||||
"hand_left": {
|
||||
"rotation": [0, 0, 10]
|
||||
},
|
||||
"bottom_coat": {
|
||||
"rotation": ["0-(math.cos(q.anim_time*90*2*1+180)*3)*0.6", 0, 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": ["0+(math.sin(q.anim_time*90*2*1+180)*3)*0.6", 0, "0-(math.sin(q.anim_time*90*2*1+180)*3)*0.6"]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": ["0+(math.sin(q.anim_time*90*2*1+180)*3)*0.6", 0, "0+(math.sin(q.anim_time*90*2*1+180)*3)*0.6"]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -84,157 +53,47 @@
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": ["25+math.cos(query.anim_time*90*3/2)*2", "0+math.cos(query.anim_time*90*3/2/2)*4", "0+math.cos(query.anim_time*90*3/2/2-60)*2"],
|
||||
"position": ["0-math.cos(query.anim_time*90*3/2/2-30)*1", "3+math.sin(query.anim_time*90*3/2)*0.7", "0-math.sin(query.anim_time*90*3/2-60)*1"]
|
||||
"rotation": ["17.5-(math.cos(q.anim_time*90*2*1+180)*10)*0.6", 0, "0-(math.sin(q.anim_time*90*2*1+180)*1)*0.6"],
|
||||
"position": [0, "2+(math.cos(q.anim_time*90*2*1+180)*1.5)*0.6", "0+(math.sin(q.anim_time*90*2*1+180)*1.8)*0.6"]
|
||||
},
|
||||
"torso_top": {
|
||||
"rotation": ["10-math.cos(query.anim_time*90*3/2-30)*2", "0+math.cos(query.anim_time*90*3/2/2)*4", 0]
|
||||
"rotation": ["0+(math.cos(q.anim_time*90*2*1+180)*3)*0.6", 0, 0]
|
||||
},
|
||||
"collar_back": {
|
||||
"rotation": ["-15+math.cos(query.anim_time*90*3/2-30)*2", "0+math.cos(query.anim_time*90*3/2/2-90)*2", 0]
|
||||
"rotation": ["0-(math.cos(q.anim_time*90*2*1+180)*6)*0.6", 0, 0]
|
||||
},
|
||||
"collar_front": {
|
||||
"rotation": ["27.5-math.cos(query.anim_time*90*3/2-60)*1", 0, 0]
|
||||
},
|
||||
"eyes_bright": {
|
||||
"position": [0, 0, -0.1]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [
|
||||
"20.433+math.cos(query.anim_time*90*3/2/2-120)*7",
|
||||
"31.8177-math.cos(query.anim_time*90*3/2-60)*6",
|
||||
"-45.313-math.cos(query.anim_time*90*3/2-90)*2"
|
||||
]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [
|
||||
"39.442+math.cos(query.anim_time*90*3/2-90)*6",
|
||||
"-27.7035+math.cos(query.anim_time*90*3/2-90)*8",
|
||||
"-8.2892-math.cos(query.anim_time*90*3/2-120)*6"
|
||||
]
|
||||
},
|
||||
"hand_right": {
|
||||
"rotation": [19.42631, "0.9236-math.cos(query.anim_time*90*3/2-120)*5", "-39.9562+math.cos(query.anim_time*90*3/2-150)*6"]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [
|
||||
"20.433+math.cos(query.anim_time*90*3/2/2-120)*7",
|
||||
"-31.8177+math.cos(query.anim_time*90*3/2-60)*6",
|
||||
"45.313+math.cos(query.anim_time*90*3/2-90)*2"
|
||||
]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [
|
||||
"39.442+math.cos(query.anim_time*90*3/2-90)*6",
|
||||
"27.7035-math.cos(query.anim_time*90*3/2-90)*8",
|
||||
"8.2892+math.cos(query.anim_time*90*3/2-120)*6"
|
||||
]
|
||||
},
|
||||
"hand_left": {
|
||||
"rotation": [19.42631, "-0.9236+math.cos(query.anim_time*90*3/2-120)*5", "39.9562-math.cos(query.anim_time*90*3/2-150)*6"]
|
||||
},
|
||||
"torso_bottom": {
|
||||
"rotation": ["2.5+math.cos(query.anim_time*90*3/2-60)*2", 0, "0+math.cos(query.anim_time*90*3/2/2-60)*4"]
|
||||
},
|
||||
"bottom_coat": {
|
||||
"rotation": ["-8+math.cos(query.anim_time*90*3/2-90)*2", "0+math.cos(query.anim_time*90*3/2/2-120)*2", "0+math.cos(query.anim_time*90*3/2/2-120)*2"]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": ["4.5574+math.cos(query.anim_time*90*3/2-120)*6", 10.64348, 7.53105]
|
||||
},
|
||||
"leg_right2": {
|
||||
"rotation": ["22.5+math.cos(query.anim_time*90*3/2-170)*10", 0, 0]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": ["4.5574+math.cos(query.anim_time*90*3/2-120)*6", -10.64348, -7.53105]
|
||||
},
|
||||
"leg_left2": {
|
||||
"rotation": ["22.5+math.cos(query.anim_time*90*3/2-170)*10", 0, 0]
|
||||
},
|
||||
"eyes_dim": {
|
||||
"position": [0, 0, 0.1]
|
||||
"rotation": ["0+(math.cos(q.anim_time*90*2*1+180)*6)*0.6", 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["-12.5+math.cos(query.anim_time*90*3/2)*3", "0-math.cos(query.anim_time*90*3/2/2)*4", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.battle_idle": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": ["-5+math.cos(query.anim_time*90*1)*2", 0, "0+math.cos(query.anim_time*90*1/2)*1"],
|
||||
"position": ["0+math.sin(query.anim_time*90*1/2)*0.5", "3+math.sin(query.anim_time*90*1)*0.5", 0]
|
||||
},
|
||||
"torso_top": {
|
||||
"rotation": ["2.5-math.cos(query.anim_time*90*1-30)*2", 0, "0+math.cos(query.anim_time*90*1/2-60)*2"]
|
||||
},
|
||||
"collar_back": {
|
||||
"rotation": ["7.5+math.cos(query.anim_time*90*1-30)*2", 0, 0]
|
||||
},
|
||||
"collar_front": {
|
||||
"rotation": ["27.5-math.cos(query.anim_time*90*1-60)*1", 0, 0]
|
||||
},
|
||||
"eyes_bright": {
|
||||
"position": [0, 0, -0.1]
|
||||
"rotation": ["0+(math.cos(q.anim_time*90*2*1+180)*6)*0.6", 0, 0]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [
|
||||
"19.1787+math.cos(query.anim_time*90*1/2-120)*4",
|
||||
"22.2175-math.cos(query.anim_time*90*1-60)*3",
|
||||
"-48.3831-math.cos(query.anim_time*90*1-90)*2"
|
||||
]
|
||||
"rotation": [0, "20-(math.sin(q.anim_time*90*2*1+180)*3)*0.6", "-55-(math.sin(q.anim_time*90*2*1+180)*6)*0.6"]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": ["38.8131+math.cos(query.anim_time*90*1-90)*6", "-35.024+math.cos(query.anim_time*90*1-90)*4", "3.02+math.cos(query.anim_time*90*1-120)*2"]
|
||||
"rotation": ["-(math.cos(q.anim_time*90*2*1+180)*6)*0.6", 0, "0+(math.cos(q.anim_time*90*2*1+180)*1)*0.6"]
|
||||
},
|
||||
"hand_right": {
|
||||
"rotation": [17.41964, "-20.6269-math.cos(query.anim_time*90*1-120)*3", "-23.4374+math.cos(query.anim_time*90*1-150)*8"]
|
||||
"rotation": [0, 0, -10]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [
|
||||
"19.1787+math.cos(query.anim_time*90*1/2-120)*4",
|
||||
"-22.2175+math.cos(query.anim_time*90*1-60)*3",
|
||||
"48.3831+math.cos(query.anim_time*90*1-90)*2"
|
||||
]
|
||||
"rotation": [0, "-20+(math.sin(q.anim_time*90*2*1+180)*3)*0.6", "55+(math.sin(q.anim_time*90*2*1+180)*6)*0.6"]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": ["38.8131+math.cos(query.anim_time*90*1-90)*6", "35.024-math.cos(query.anim_time*90*1-90)*4", "-3.02-math.cos(query.anim_time*90*1-120)*2"]
|
||||
"rotation": ["(math.cos(q.anim_time*90*2*1+180)*6)*0.6", 0, "0-(math.cos(q.anim_time*90*2*1+180)*1)*0.6"]
|
||||
},
|
||||
"hand_left": {
|
||||
"rotation": [17.41964, "20.6269+math.cos(query.anim_time*90*1-120)*3", "23.4374-math.cos(query.anim_time*90*1-150)*8"]
|
||||
},
|
||||
"torso_bottom": {
|
||||
"rotation": ["-7.5+math.cos(query.anim_time*90*1-60)*2", 0, "0-math.cos(query.anim_time*90*1/2-120)*1"]
|
||||
"rotation": [0, 0, 10]
|
||||
},
|
||||
"bottom_coat": {
|
||||
"rotation": ["-10.5+math.cos(query.anim_time*90*1-90)*2", 0, "-math.cos(query.anim_time*90*1/2-90)*2"]
|
||||
"rotation": ["-2.5-(math.cos(q.anim_time*90*2*1+180)*6)*0.6", 0, 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": ["2.0651+math.cos(query.anim_time*90*1-120)*6", 9.9897, "-0.1242-math.cos(query.anim_time*90*1/2-90)*4"]
|
||||
},
|
||||
"leg_right2": {
|
||||
"rotation": ["22.5+math.cos(query.anim_time*90*1-170)*10", 0, "NaN-math.cos(query.anim_time*90*1/2-150)*3"]
|
||||
"rotation": ["0-(math.cos(q.anim_time*90*2*1+180)*5)*2", 0, "0-(math.cos(q.anim_time*90*2*1+180)*1)*2"]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": ["2.9483+math.cos(query.anim_time*90*1-120)*6", -10.03277, "-4.953-math.cos(query.anim_time*90*1/2-90)*4"]
|
||||
},
|
||||
"leg_left2": {
|
||||
"rotation": ["22.5+math.cos(query.anim_time*90*1-170)*10", 0, "-math.cos(query.anim_time*90*1/2-150)*3"]
|
||||
},
|
||||
"pupil_left": {
|
||||
"position": [0, 0, -0.1],
|
||||
"scale": 0.75
|
||||
},
|
||||
"pupil_right": {
|
||||
"position": [0, 0, -0.1],
|
||||
"scale": 0.75
|
||||
},
|
||||
"eyes_dim": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["25+math.cos(query.anim_time*90*1)*1", 0, "0-math.cos(query.anim_time*90*1/2-120)*3"]
|
||||
"rotation": ["0-(math.cos(q.anim_time*90*2*1+180)*5)*2", 0, "0+(math.cos(q.anim_time*90*2*1+180)*1)*2"]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -242,341 +101,50 @@
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [40, 0, 0],
|
||||
"position": [0, 3, 0]
|
||||
"rotation": ["0+(math.sin(q.anim_time*90*1+180)*1.5)*0.6", 0, "0+(math.sin(q.anim_time*90*1+180)*3)*0.6"],
|
||||
"position": [0, "1+(math.cos(q.anim_time*90*1+180)*0.8)*0.6", 0]
|
||||
},
|
||||
"torso_top": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
"rotation": ["0+(math.sin(q.anim_time*90*1+180)*5)*0.6", 0, 0]
|
||||
},
|
||||
"collar_back": {
|
||||
"rotation": [10, 0, 0]
|
||||
"rotation": ["0-(math.cos(q.anim_time*90*1+180)*3)*0.6", 0, 0]
|
||||
},
|
||||
"collar_front": {
|
||||
"rotation": [-15, 0, 0]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [30.18785, -13.49583, -55.38615]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [8.0521, -19.65857, 17.64818]
|
||||
},
|
||||
"hand_right": {
|
||||
"rotation": [12.21635, -29.21703, -28.76232]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [30.18785, 13.49583, 55.38615]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [8.0521, 19.65857, -17.64818]
|
||||
},
|
||||
"hand_left": {
|
||||
"rotation": [12.21635, 29.21703, 28.76232]
|
||||
},
|
||||
"torso_bottom": {
|
||||
"rotation": [-17.5, 0, 0]
|
||||
},
|
||||
"bottom_coat": {
|
||||
"rotation": [-17.5, 0, 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": [-22.5, 0, 0]
|
||||
},
|
||||
"leg_right2": {
|
||||
"rotation": [10, 0, 0]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": [-10, 0, 0]
|
||||
"rotation": ["0-(math.cos(q.anim_time*90*1+180)*3)*0.6", 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [20, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.alt_sleep": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [-52.5, 0, 0],
|
||||
"position": [0, 3, 0]
|
||||
},
|
||||
"torso_top": {
|
||||
"rotation": [2.5, 0, 0]
|
||||
},
|
||||
"collar_back": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"collar_front": {
|
||||
"rotation": [27.5, 0, 0]
|
||||
"rotation": ["25+(math.sin(q.anim_time*90*1+180)*3)*0.6", 0, 0]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [-40.58835, 28.2876, -5.84768]
|
||||
"rotation": [0, "0-(math.cos(q.anim_time*90*1+180)*10)*0.3", "-60+(math.sin(q.anim_time*90*1+180)*5)*0.6"]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [-23.10066, 18.44452, 79.80343]
|
||||
"rotation": [0, "0-(math.cos(q.anim_time*90*1+180)*10)*0.3", 0]
|
||||
},
|
||||
"hand_right": {
|
||||
"rotation": [-103.94239, -26.14027, 28.61413]
|
||||
"rotation": [0, 0, -10]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [-40.58835, -28.2876, 5.84768]
|
||||
"rotation": [0, "0+(math.cos(q.anim_time*90*1+180)*10)*0.3", "60-(math.sin(q.anim_time*90*1+180)*5)*0.6"]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [-23.10066, -18.44452, -79.80343]
|
||||
"rotation": [0, "0+(math.cos(q.anim_time*90*1+180)*10)*0.3", 0]
|
||||
},
|
||||
"hand_left": {
|
||||
"rotation": [-103.94239, 26.14027, -28.61413]
|
||||
"rotation": [0, 0, 10]
|
||||
},
|
||||
"torso_bottom": {
|
||||
"rotation": [-12.5, 0, 0]
|
||||
"rotation": ["0+(math.sin(q.anim_time*90*1+180)*5)*0.6", 0, 0]
|
||||
},
|
||||
"bottom_coat": {
|
||||
"rotation": [-17.5, 0, 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": [-19.76968, -1.50179, -17.43745]
|
||||
},
|
||||
"leg_right2": {
|
||||
"rotation": [10, 0, 0]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": [17.24721, -1.93597, 14.87739]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.blink": {
|
||||
"animation_length": 0.1667,
|
||||
"bones": {
|
||||
"eyes_bright": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.125": [0, 0, 0.1],
|
||||
"0.1667": {"pre": [0, 0, 0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.pose": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [-2.5, 0, 0],
|
||||
"position": [0, 3, 0]
|
||||
},
|
||||
"torso_top": {
|
||||
"rotation": [2.5, 0, 0]
|
||||
},
|
||||
"collar_back": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"collar_front": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"eyes_bright": {
|
||||
"position": [0, 0, -0.1]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [0.18641, 11.50404, -55.30513]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [24.59434, -22.85086, 0.87852]
|
||||
},
|
||||
"hand_right": {
|
||||
"rotation": [19.6995, -3.27667, -28.1772]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [0.18641, -11.50404, 55.30513]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [24.59434, 22.85086, -0.87852]
|
||||
},
|
||||
"hand_left": {
|
||||
"rotation": [19.6995, 3.27667, 28.1772]
|
||||
},
|
||||
"torso_bottom": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
},
|
||||
"bottom_coat": {
|
||||
"rotation": [-17.5, 0, 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": [-5, 0, 0]
|
||||
},
|
||||
"leg_right2": {
|
||||
"rotation": [10, 0, 0]
|
||||
"rotation": ["0+(math.sin(q.anim_time*90*1+180)*20)*0.6", 0, "0+(math.cos(q.anim_time*90*1+180)*5)*0.6"]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"leg_left2": {
|
||||
"rotation": [15, 0, 0]
|
||||
},
|
||||
"eyes_dim": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [10, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.lights_quirk1": {
|
||||
"loop": true,
|
||||
"animation_length": 1.5,
|
||||
"bones": {
|
||||
"right_finger_bright_red2": {
|
||||
"scale": {
|
||||
"0.0": [1.05, 1.05, 1.05],
|
||||
"0.5": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"1.0": [1, 1, 1],
|
||||
"1.5": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]}
|
||||
}
|
||||
},
|
||||
"right_finger_bright_yellow": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.5": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"1.0": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"1.5": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"right_finger_bright_green2": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.5": [1, 1, 1],
|
||||
"1.0": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"1.5": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]}
|
||||
}
|
||||
},
|
||||
"left_finger_bright_red2": {
|
||||
"scale": {
|
||||
"0.0": [1.05, 1.05, 1.05],
|
||||
"0.5": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"1.0": [1, 1, 1],
|
||||
"1.5": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]}
|
||||
}
|
||||
},
|
||||
"left_finger_bright_yellow": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.5": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"1.0": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"1.5": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"left_finger_bright_green2": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.5": [1, 1, 1],
|
||||
"1.0": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"1.5": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.lights_quirk2": {
|
||||
"loop": true,
|
||||
"animation_length": 1,
|
||||
"bones": {
|
||||
"right_finger_bright_red2": {
|
||||
"scale": {
|
||||
"0.0": [1.05, 1.05, 1.05],
|
||||
"0.3333": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"0.6667": [1, 1, 1],
|
||||
"1.0": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]}
|
||||
}
|
||||
},
|
||||
"right_finger_bright_yellow": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.3333": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"0.6667": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"1.0": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"right_finger_bright_green2": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.3333": [1, 1, 1],
|
||||
"0.6667": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"1.0": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]}
|
||||
}
|
||||
},
|
||||
"left_finger_bright_red2": {
|
||||
"scale": {
|
||||
"0.0": [1.05, 1.05, 1.05],
|
||||
"0.3333": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"0.6667": [1, 1, 1],
|
||||
"1.0": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]}
|
||||
}
|
||||
},
|
||||
"left_finger_bright_yellow": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.3333": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"0.6667": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"1.0": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"left_finger_bright_green2": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.3333": [1, 1, 1],
|
||||
"0.6667": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"1.0": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.lights_quirk3": {
|
||||
"loop": true,
|
||||
"animation_length": 0.5,
|
||||
"bones": {
|
||||
"right_finger_bright_red2": {
|
||||
"scale": {
|
||||
"0.0": [1.05, 1.05, 1.05],
|
||||
"0.1667": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"0.3333": [1, 1, 1],
|
||||
"0.5": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]}
|
||||
}
|
||||
},
|
||||
"right_finger_bright_yellow": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.1667": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"0.3333": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"0.5": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"right_finger_bright_green2": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.1667": [1, 1, 1],
|
||||
"0.3333": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"0.5": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]}
|
||||
}
|
||||
},
|
||||
"left_finger_bright_red2": {
|
||||
"scale": {
|
||||
"0.0": [1.05, 1.05, 1.05],
|
||||
"0.1667": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"0.3333": [1, 1, 1],
|
||||
"0.5": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]}
|
||||
}
|
||||
},
|
||||
"left_finger_bright_yellow": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.1667": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"0.3333": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]},
|
||||
"0.5": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"left_finger_bright_green2": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
"0.1667": [1, 1, 1],
|
||||
"0.3333": {"pre": [1, 1, 1], "post": [1.05, 1.05, 1.05]},
|
||||
"0.5": {"pre": [1.05, 1.05, 1.05], "post": [1, 1, 1]}
|
||||
}
|
||||
"rotation": ["0-(math.sin(q.anim_time*90*1+180)*20)*0.6", 0, "0-(math.cos(q.anim_time*90*1+180)*5)*0.6"]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -610,6 +178,15 @@
|
||||
"1.4583": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": {
|
||||
"0.0": ["0+(math.cos(q.anim_time*90*2*1+180)*0.8)*0.6", 0, 0],
|
||||
"0.125": [11.5, 0, 0],
|
||||
"0.4167": ["-6-(math.cos(q.anim_time*90*80+180)*2)*2", 0, 0],
|
||||
"0.9583": ["-6+(math.cos(q.anim_time*90*8+180)*2)*0.6", 0, 0],
|
||||
"1.4583": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, 0],
|
||||
@@ -645,94 +222,11 @@
|
||||
"0.9583": [7.3679, 40.2246, -30.8095],
|
||||
"1.4583": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": {
|
||||
"0.0": ["0+(math.cos(q.anim_time*90*2*1+180)*0.8)*0.6", 0, 0],
|
||||
"0.125": [11.5, 0, 0],
|
||||
"0.4167": ["-6-(math.cos(q.anim_time*90*80+180)*2)*2", 0, 0],
|
||||
"0.9583": ["-6+(math.cos(q.anim_time*90*8+180)*2)*0.6", 0, 0],
|
||||
"1.4583": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.new": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"beheeyem": {
|
||||
"position": [0, 0, "33-query.anim_time*90*0.08"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.beheeyem.pose2": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [-2.5, 0, 0],
|
||||
"position": [0, 3, 0]
|
||||
},
|
||||
"torso_top": {
|
||||
"rotation": [2.5, 0, 0]
|
||||
},
|
||||
"collar_back": {
|
||||
"rotation": [5, 0, 0]
|
||||
},
|
||||
"collar_front": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"eyes_bright": {
|
||||
"position": [0, 0, -0.1]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [-16.69715, -44.79233, -31.70444]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [24.59434, -22.85086, 0.87852]
|
||||
},
|
||||
"hand_right": {
|
||||
"rotation": [19.6995, -3.27667, -28.1772]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [0.18641, -11.50404, 55.30513]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [24.59434, 22.85086, -0.87852]
|
||||
},
|
||||
"hand_left": {
|
||||
"rotation": [19.6995, 3.27667, 28.1772]
|
||||
},
|
||||
"torso_bottom": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
},
|
||||
"bottom_coat": {
|
||||
"rotation": [-17.5, 0, 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": [-5, 0, 0]
|
||||
},
|
||||
"leg_right2": {
|
||||
"rotation": [10, 0, 0]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
},
|
||||
"leg_left2": {
|
||||
"rotation": [15, 0, 0]
|
||||
},
|
||||
"pupil_left": {
|
||||
"position": [-0.25, 0, -0.1],
|
||||
"scale": 0.75
|
||||
},
|
||||
"pupil_right": {
|
||||
"position": [-0.25, 0, -0.1],
|
||||
"scale": 0.75
|
||||
},
|
||||
"eyes_dim": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [10, 0, 0]
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.beheeyem.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+40
-113
@@ -26,9 +26,6 @@
|
||||
},
|
||||
"eyes": {
|
||||
"scale": [1, "1-math.sin(q.anim_time*90)*0.03", 1]
|
||||
},
|
||||
"wax_trail": {
|
||||
"position": [0, 0.02, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -46,7 +43,7 @@
|
||||
"scale": [1, "1-math.sin(q.anim_time*90*4-135)*0.01", 1]
|
||||
},
|
||||
"flame": {
|
||||
"rotation": ["-2.5+(math.sin(q.anim_time*90)*6)*(math.sin(q.anim_time*90-90))", 0, "0-(math.sin(q.anim_time*90-45)*6)*(math.sin(q.anim_time*90-90))"],
|
||||
"rotation": ["(math.sin(q.anim_time*90)*6)*(math.sin(q.anim_time*90-90))", 0, "-(math.sin(q.anim_time*90-45)*6)*(math.sin(q.anim_time*90-90))"],
|
||||
"scale": [1, "1+math.sin(q.anim_time*90*4+125)*0.1", 1]
|
||||
},
|
||||
"arm_right": {
|
||||
@@ -64,10 +61,7 @@
|
||||
"scale": [1, "1+math.sin(q.anim_time*90*4+90)*0.01", 1]
|
||||
},
|
||||
"wax_trail2": {
|
||||
"scale": [1, 1, "1-math.sin(q.anim_time*90*4+75)*0.1"]
|
||||
},
|
||||
"wax_trail": {
|
||||
"position": [0, 0.03, 0]
|
||||
"position": [0, 0, "0.3-math.sin(q.anim_time*90*4+75)*0.33"]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -106,7 +100,7 @@
|
||||
"position": ["(math.sin(q.anim_time*90*2)*0.5)", 0, 0]
|
||||
},
|
||||
"wax_trail": {
|
||||
"position": ["(math.sin(q.anim_time*90*2-90)*0.2)", 0.02, 0],
|
||||
"position": ["(math.sin(q.anim_time*90*2-90)*0.2)", 0, 0],
|
||||
"scale": ["1+(math.sin(q.anim_time*90*4+45)*0.04)", 1, 1]
|
||||
},
|
||||
"lip": {
|
||||
@@ -147,7 +141,7 @@
|
||||
"scale": [1, 0.9, 1]
|
||||
},
|
||||
"wax_trail": {
|
||||
"position": [0, 0.52, 0],
|
||||
"position": [0, 0.5, 0],
|
||||
"scale": 1.075
|
||||
},
|
||||
"eyelid_right": {
|
||||
@@ -159,129 +153,62 @@
|
||||
"lip": {
|
||||
"rotation": [4.98, 0, 0],
|
||||
"position": [0, 0, -0.008]
|
||||
},
|
||||
"eye_left_open": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"eye_closed_left": {
|
||||
"position": [0, 0, -0.1]
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"eye_closed_right": {
|
||||
"position": [0, 0, -0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.litwick.blink": {
|
||||
"animation_length": 0.1667,
|
||||
"animation_length": 0.20833,
|
||||
"bones": {
|
||||
"eye_left_open": {
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.125": [0, 0, 0.1],
|
||||
"0.1667": [0, 0, 0]
|
||||
"0.0": [-0.1, 0, -0.1],
|
||||
"0.1667": [-0.1, 0, -0.1],
|
||||
"0.2083": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"eye_closed_left": {
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, -0.1],
|
||||
"0.125": [0, 0, -0.1],
|
||||
"0.1667": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0.1],
|
||||
"0.125": [0, 0, 0.1],
|
||||
"0.1667": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"eye_closed_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, -0.1],
|
||||
"0.125": [0, 0, -0.1],
|
||||
"0.1667": [0, 0, 0]
|
||||
"0.0": [0.1, 0, -0.1],
|
||||
"0.1667": [0.1, 0, -0.1],
|
||||
"0.2083": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.litwick.shock": {
|
||||
"animation.litwick.pose": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_left_open": {
|
||||
"position": [0, 0.25, 0],
|
||||
"scale": [1, 0.5, 1]
|
||||
"head": {
|
||||
"rotation": [-7.56397, -7.43547, 0.98448]
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": [0, 0.25, 0]
|
||||
"hair": {
|
||||
"rotation": [-2.5, 0, 0]
|
||||
},
|
||||
"mouth_open": {
|
||||
"position": [0, 0, -0.1],
|
||||
"scale": [0.9, 1, 1]
|
||||
"flame": {
|
||||
"rotation": [-19.8423, -2.55868, -12.05239]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [0, 0, -50]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [0, 0, 52.5]
|
||||
},
|
||||
"lip": {
|
||||
"rotation": [-7.5, 0, 0]
|
||||
},
|
||||
"mouth_small": {
|
||||
"position": [0, 0, 0]
|
||||
},
|
||||
"mouth_large": {
|
||||
"position": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.litwick.angry": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_expression_left": {
|
||||
"position": [-0.5, 0, -0.1]
|
||||
},
|
||||
"eye_expression_right": {
|
||||
"position": [0.5, 0, -0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.litwick.sad": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_expression_left": {
|
||||
"position": [0.5, 0, -0.1]
|
||||
},
|
||||
"eye_expression_right": {
|
||||
"position": [-0.5, 0, -0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.litwick.happy": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_left_open": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"eye_happy_left": {
|
||||
"position": [0, 0, -0.1]
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"eye_happy_right": {
|
||||
"position": [0, 0, -0.1]
|
||||
},
|
||||
"mouth_open": {
|
||||
"position": [0, 0, -0.1],
|
||||
"scale": [0.9, 1, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.litwick.hurt": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_left_open": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"eye_closed_left": {
|
||||
"rotation": [0, 0, -27.5],
|
||||
"position": [0, 0, -0.1]
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"eye_closed_right": {
|
||||
"rotation": [0, 0, 27.5],
|
||||
"position": [0, 0, -0.1]
|
||||
"animation.litwick.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.litwick.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+79
-155
@@ -20,7 +20,7 @@
|
||||
"rotation": ["-2.5 + math.sin(q.anim_time*90*2-90)", 5, "7.5 + 5*math.sin(q.anim_time*90*2)"]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [0, 0, "5*math.sin(q.anim_time*90*2+90)"]
|
||||
"rotation": [0, 0, "10 + 5*math.sin(q.anim_time*90*2+90)"]
|
||||
},
|
||||
"arm_left3": {
|
||||
"rotation": [0, 0, "10 + 5*math.sin(q.anim_time*90*2+180)"]
|
||||
@@ -38,7 +38,7 @@
|
||||
"rotation": ["-2.5+math.sin(q.anim_time*90*2-90)", -5, "-7.5 - 5*math.sin(q.anim_time*90*2)"]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [0, 0, "- 5*math.sin(q.anim_time*90*2+90)"]
|
||||
"rotation": [0, 0, "-10 - 5*math.sin(q.anim_time*90*2+90)"]
|
||||
},
|
||||
"arm_right3": {
|
||||
"rotation": [0, 0, "-10 - 5*math.sin(q.anim_time*90*2+180)"]
|
||||
@@ -59,13 +59,7 @@
|
||||
"scale": 0
|
||||
},
|
||||
"body": {
|
||||
"position": [0, 1, 0]
|
||||
},
|
||||
"arm_left7": {
|
||||
"rotation": [0, 0, 57.5]
|
||||
},
|
||||
"arm_right7": {
|
||||
"rotation": [0, 0, -57.5]
|
||||
"position": [0, 4, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -88,7 +82,7 @@
|
||||
"rotation": ["10.2854 + math.sin(q.anim_time*90*2-90)*2", 6.26335, "18.6835 + 5*math.sin(q.anim_time*90*2)"]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [0, 0, "10.5 + 5*math.sin(q.anim_time*90*2+90)"]
|
||||
"rotation": [0, 0, "18 + 5*math.sin(q.anim_time*90*2+90)"]
|
||||
},
|
||||
"arm_left3": {
|
||||
"rotation": [0, 0, "20 + 5*math.sin(q.anim_time*90*2+180)"]
|
||||
@@ -106,7 +100,7 @@
|
||||
"rotation": ["10.2854 + math.sin(q.anim_time*90*2-90)*2", -6.26335, "-18.6835+ 5*math.sin(q.anim_time*90*2)"]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [0, 0, "-10.5+ 5*math.sin(q.anim_time*90*2+90)"]
|
||||
"rotation": [0, 0, "-18+ 5*math.sin(q.anim_time*90*2+90)"]
|
||||
},
|
||||
"arm_right3": {
|
||||
"rotation": [0, 0, "-20+ 5*math.sin(q.anim_time*90*2+180)"]
|
||||
@@ -131,12 +125,6 @@
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, 0, 0]
|
||||
},
|
||||
"arm_left7": {
|
||||
"rotation": [0, 0, 57.5]
|
||||
},
|
||||
"arm_right7": {
|
||||
"rotation": [-2.50463, -13.04546, -71.15153]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -199,12 +187,6 @@
|
||||
},
|
||||
"body": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"arm_left7": {
|
||||
"rotation": [0, 0, 47.5]
|
||||
},
|
||||
"arm_right7": {
|
||||
"rotation": [0, 0, -47.5]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -227,7 +209,7 @@
|
||||
"rotation": ["10.2854 + math.sin(q.anim_time*90*2-90)*2", 6.26335, "18.6835 + 5*math.sin(q.anim_time*90*2)"]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [0, 0, "10.5 + 5*math.sin(q.anim_time*90*2+90)"]
|
||||
"rotation": [0, 0, "18 + 5*math.sin(q.anim_time*90*2+90)"]
|
||||
},
|
||||
"arm_left3": {
|
||||
"rotation": [0, 0, "20 + 5*math.sin(q.anim_time*90*2+180)"]
|
||||
@@ -245,7 +227,7 @@
|
||||
"rotation": ["10.2854 + math.sin(q.anim_time*90*2-90)*2", -6.26335, "-18.6835+ 5*math.sin(q.anim_time*90*2)"]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [0, 0, "-10.5+ 5*math.sin(q.anim_time*90*2+90)"]
|
||||
"rotation": [0, 0, "-18+ 5*math.sin(q.anim_time*90*2+90)"]
|
||||
},
|
||||
"arm_right3": {
|
||||
"rotation": [0, 0, "-20+ 5*math.sin(q.anim_time*90*2+180)"]
|
||||
@@ -270,12 +252,6 @@
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, 0, 0]
|
||||
},
|
||||
"arm_left7": {
|
||||
"rotation": [0, 0, 57.5]
|
||||
},
|
||||
"arm_right7": {
|
||||
"rotation": [0, 0, -57.5]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -321,13 +297,13 @@
|
||||
"rotation": [0, 0, "22+5*math.sin(q.anim_time*90*2)*0.5"]
|
||||
},
|
||||
"arm_right3": {
|
||||
"rotation": [0, 0, "25+5*math.sin(q.anim_time*90*2)"]
|
||||
"rotation": [0, 0, "35+5*math.sin(q.anim_time*90*2)"]
|
||||
},
|
||||
"arm_right4": {
|
||||
"rotation": [0, 0, "19.5+5*math.sin(q.anim_time*90*2)*0.5"]
|
||||
},
|
||||
"arm_right5": {
|
||||
"rotation": [0, 0, "15+5*math.sin(q.anim_time*90*2)*0.5"]
|
||||
"rotation": [0, 0, "30+5*math.sin(q.anim_time*90*2)*0.5"]
|
||||
},
|
||||
"arm_right6": {
|
||||
"rotation": [0, 0, "24+5*math.sin(q.anim_time*90*2)*0.5"]
|
||||
@@ -340,12 +316,6 @@
|
||||
},
|
||||
"body": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"arm_left7": {
|
||||
"rotation": [0, 0, 70]
|
||||
},
|
||||
"arm_right7": {
|
||||
"rotation": [0, 0, 12.5]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -409,29 +379,31 @@
|
||||
"body": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"arm_left7": {
|
||||
"rotation": [0, 0, 67.5]
|
||||
"eye_left": {
|
||||
"scale": 0
|
||||
},
|
||||
"arm_right7": {
|
||||
"rotation": [0, 0, -67.5]
|
||||
},
|
||||
"eye_left_open": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"eye_closed_left": {
|
||||
"position": [0, -4, 0]
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"eye_closed_right": {
|
||||
"position": [0, -4, 0]
|
||||
"eye_right": {
|
||||
"scale": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lampent.blink": {
|
||||
"animation_length": 0.1667,
|
||||
"animation_length": 0.16667,
|
||||
"bones": {
|
||||
"eye_left": {
|
||||
"scale": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.125": [0, 0, 0],
|
||||
"0.1667": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"eye_right": {
|
||||
"scale": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.125": [0, 0, 0],
|
||||
"0.1667": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"scale": {
|
||||
"0.0": [1, 1, 1],
|
||||
@@ -445,116 +417,68 @@
|
||||
"0.125": [1, 1, 1],
|
||||
"0.1667": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
"eye_left_open": {
|
||||
"position": {
|
||||
"0.0": [0, 4, 0],
|
||||
"0.125": {"pre": [0, 4, 0], "post": [0, 4, 0]},
|
||||
"0.1667": {"pre": [0, 4, 0], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eye_closed_left": {
|
||||
"position": {
|
||||
"0.0": [0, -4, 0],
|
||||
"0.125": {"pre": [0, -4, 0], "post": [0, -4, 0]},
|
||||
"0.1667": {"pre": [0, -4, 0], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": {
|
||||
"0.0": [0, 4, 0],
|
||||
"0.125": {"pre": [0, 4, 0], "post": [0, 4, 0]},
|
||||
"0.1667": {"pre": [0, 4, 0], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"eye_closed_right": {
|
||||
"position": {
|
||||
"0.0": [0, -4, 0],
|
||||
"0.125": {"pre": [0, -4, 0], "post": [0, -4, 0]},
|
||||
"0.1667": {"pre": [0, -4, 0], "post": [0, 0, 0]}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lampent.shock": {
|
||||
"animation.lampent.pose": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_left_open": {
|
||||
"position": [0, 0.25, 0],
|
||||
"scale": [0.7, 0.7, 1]
|
||||
"body": {
|
||||
"rotation": [0, -5, 7.5]
|
||||
},
|
||||
"eye_left_open2": {
|
||||
"scale": 0
|
||||
"head": {
|
||||
"rotation": [14.60945, 2.9986, -5.59467]
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": [0, 0.25, 0],
|
||||
"scale": [0.7, 0.7, 1]
|
||||
"arm_left": {
|
||||
"rotation": [0, 25, -7.5]
|
||||
},
|
||||
"eye_right_open2": {
|
||||
"position": [-0.25, -0.25, 0],
|
||||
"scale": 0
|
||||
"arm_left2": {
|
||||
"rotation": [0, 0, -22.5]
|
||||
},
|
||||
"arm_left3": {
|
||||
"rotation": [0, 0, -17.5]
|
||||
},
|
||||
"arm_left4": {
|
||||
"rotation": [0, 0, -22.5]
|
||||
},
|
||||
"arm_left5": {
|
||||
"rotation": [0, 0, -30]
|
||||
},
|
||||
"arm_left6": {
|
||||
"rotation": [0, 0, -28.5]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [0, 0, -5]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [0, 0, -20]
|
||||
},
|
||||
"arm_right3": {
|
||||
"rotation": [0, 0, -25]
|
||||
},
|
||||
"arm_right4": {
|
||||
"rotation": [0, 0, -40]
|
||||
},
|
||||
"arm_right5": {
|
||||
"rotation": [0, 0, -38.5]
|
||||
},
|
||||
"arm_right6": {
|
||||
"rotation": [0, 0, -36.5]
|
||||
},
|
||||
"swing": {
|
||||
"rotation": [-13.63677, 25.79103, 6.17047],
|
||||
"position": [4.2, 4, 11]
|
||||
},
|
||||
"flame": {
|
||||
"rotation": [0, 22.5, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lampent.angry": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_left_open2": {
|
||||
"position": [0.25, -0.25, 0],
|
||||
"scale": [0.5, 0.5, 1]
|
||||
},
|
||||
"eye_right_open2": {
|
||||
"position": [-0.25, -0.25, 0],
|
||||
"scale": [0.5, 0.5, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lampent.sad": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_left_open2": {
|
||||
"position": [-0.25, -0.25, 0],
|
||||
"scale": [0.5, 0.5, 1]
|
||||
},
|
||||
"eye_right_open2": {
|
||||
"position": [0.25, -0.25, 0],
|
||||
"scale": [0.5, 0.5, 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lampent.happy": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_left_open": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"eye_happy_left": {
|
||||
"position": [0, -4, 0]
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"eye_happy_right": {
|
||||
"position": [0, -4, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lampent.hurt": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_left_open": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"eye_closed_left": {
|
||||
"rotation": [0, 0, -20],
|
||||
"position": [0, -4, 0]
|
||||
},
|
||||
"eye_right_open": {
|
||||
"position": [0, 4, 0]
|
||||
},
|
||||
"eye_closed_right": {
|
||||
"rotation": [0, 0, 20],
|
||||
"position": [0, -4, 0]
|
||||
"animation.lampent.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.lampent.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+603
-626
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user