mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
185
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0af70a1433 | ||
|
|
268e7c4afc | ||
|
|
070d6f9529 | ||
|
|
8420dd6fe3 | ||
|
|
24ee96a85d | ||
|
|
32ff4ee609 | ||
|
|
7a61ce1a94 | ||
|
|
46f43345f2 | ||
|
|
baf3cd5f30 | ||
|
|
2327f1aa2c | ||
|
|
62036c0ac6 | ||
|
|
ad438bfbcd | ||
|
|
2db494ff5e | ||
|
|
7fe1415551 | ||
|
|
ca4d4ed3be | ||
|
|
700227be41 | ||
|
|
985a4f65dc | ||
|
|
e117100e34 | ||
|
|
93ea13fa4d | ||
|
|
5bc056d28e | ||
|
|
cd14881d17 | ||
|
|
1393cc3ef3 | ||
|
|
23ebd0573a | ||
|
|
6447c2e2eb | ||
|
|
039a18a2bf | ||
|
|
71736341f0 | ||
|
|
bb6e5607f1 | ||
|
|
4603f5ac7a | ||
|
|
c683294227 | ||
|
|
f29c2343e6 | ||
|
|
3a2da5a87d | ||
|
|
27d1de8e4e | ||
|
|
8af62f800b | ||
|
|
a50da47a8e | ||
|
|
f690781b0d | ||
|
|
6a7fc67ae1 | ||
|
|
4722defec2 | ||
|
|
7b7acb97d1 | ||
|
|
53af92f254 | ||
|
|
91bce4b153 | ||
|
|
511130d353 | ||
|
|
476c3e54f1 | ||
|
|
4bfe8b808c | ||
|
|
8db943d2a9 | ||
|
|
fdff6ecfa5 | ||
|
|
2eb698969d | ||
|
|
bba60f0098 | ||
|
|
8ee2c95853 | ||
|
|
77db2ce17a | ||
|
|
ff5ea6fa21 | ||
|
|
4820d78416 | ||
|
|
2f417e953c | ||
|
|
8fde0ed4f6 | ||
|
|
6715874a8f | ||
|
|
31f88a1f68 | ||
|
|
f80aa2769a | ||
|
|
20aa4d43b8 | ||
|
|
9bec3e088f | ||
|
|
5b4dbe1957 | ||
|
|
48f248d481 | ||
|
|
d726c4d0ed | ||
|
|
c9c421ba2a | ||
|
|
2436a8ddcc | ||
|
|
3364944c26 | ||
|
|
9e6a6eabc7 | ||
|
|
78def7318e | ||
|
|
fdf062bd4c | ||
|
|
ef5a682adb | ||
|
|
f76d28d29e | ||
|
|
9c70aad64d | ||
|
|
25de1ad180 | ||
|
|
f967d1ec11 | ||
|
|
efd0497de1 | ||
|
|
b30c0a4a9a | ||
|
|
c99b26a44b | ||
|
|
b19bc1e4c7 | ||
|
|
bc5ffda1a5 | ||
|
|
491d6c9fd6 | ||
|
|
ccc6ad77a5 | ||
|
|
00fd9d1278 | ||
|
|
01464f8b71 | ||
|
|
d91fe0b876 | ||
|
|
3033adcc2f | ||
|
|
252634bfde | ||
|
|
3f6faf7796 | ||
|
|
d5efdeee68 | ||
|
|
57f446260c | ||
|
|
d4cf44f8f0 | ||
|
|
a074ebbcce | ||
|
|
6578ed55e3 | ||
|
|
f567ceadd8 | ||
|
|
5de92f78c6 | ||
|
|
a2402f78e7 | ||
|
|
1ad6d63137 | ||
|
|
39d417c651 | ||
|
|
ce1bf9f4f2 | ||
|
|
a6136906f8 | ||
|
|
37a99b528e | ||
|
|
048b237302 | ||
|
|
131773f9c8 | ||
|
|
22e55b7e77 | ||
|
|
6c288f9cc8 | ||
|
|
b5e86a9460 | ||
|
|
f199e7c1c0 | ||
|
|
4161d96707 | ||
|
|
59927dd701 | ||
|
|
220d8ddc0f | ||
|
|
0dd143e67e | ||
|
|
d83eb62821 | ||
|
|
a716fda023 | ||
|
|
d14aad787c | ||
|
|
2eb7b60dd1 | ||
|
|
d79ffc631b | ||
|
|
0f38c6b00e | ||
|
|
7cd1870f23 | ||
|
|
f711f748a8 | ||
|
|
716d1b848e | ||
|
|
4878fc517d | ||
|
|
4d9d543110 | ||
|
|
718a9b922b | ||
|
|
e2a152aeb3 | ||
|
|
3e21226b27 | ||
|
|
c46c5b806c | ||
|
|
3c37d93046 | ||
|
|
c2fb914e08 | ||
|
|
7947e19337 | ||
|
|
5bde172731 | ||
|
|
496e04a779 | ||
|
|
ff4192b43c | ||
|
|
415591a443 | ||
|
|
efb1eaf3e1 | ||
|
|
7ebd2bdb94 | ||
|
|
e07579bf0a | ||
|
|
0695117549 | ||
|
|
d6cd04e2a4 | ||
|
|
8240cd10e2 | ||
|
|
2a1e749787 | ||
|
|
6d9daf692d | ||
|
|
1f7df20e77 | ||
|
|
02a4b91778 | ||
|
|
a37da4d4f2 | ||
|
|
66817b5e9b | ||
|
|
fd54e3a7e0 | ||
|
|
79f2b67bf9 | ||
|
|
2352dae6e0 | ||
|
|
9ec100f9ea | ||
|
|
7b2790de50 | ||
|
|
7f2bb84c85 | ||
|
|
17c524ab9e | ||
|
|
331e1371d4 | ||
|
|
bdd57ba1a4 | ||
|
|
670e7e9ca1 | ||
|
|
3ae349aea5 | ||
|
|
13650f98f9 | ||
|
|
d3379557fd | ||
|
|
143c2683fe | ||
|
|
72d64d36e5 | ||
|
|
c0b52c38e3 | ||
|
|
12a0ee309e | ||
|
|
824e37effd | ||
|
|
86d48df9fe | ||
|
|
3401ba9cbb | ||
|
|
dac9ccb461 | ||
|
|
191a62f693 | ||
|
|
d8d410e539 | ||
|
|
b7c6e1ea77 | ||
|
|
975cdf050f | ||
|
|
186812d6fd | ||
|
|
1c0bdc766a | ||
|
|
c697bcd2e9 | ||
|
|
9d6ff01d80 | ||
|
|
1691853a19 | ||
|
|
4e9a4e1e5a | ||
|
|
6450255a0b | ||
|
|
8fe2042127 | ||
|
|
538ad883ab | ||
|
|
136cb86492 | ||
|
|
e4eb1251d1 | ||
|
|
1bc83d9045 | ||
|
|
98775ffc1e | ||
|
|
bbeb3d45f0 | ||
|
|
8fd854f7f7 | ||
|
|
f449cf27c5 | ||
|
|
bf5fd5eed8 | ||
|
|
facead5f0b |
@@ -17,6 +17,8 @@
|
||||
- Added cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandle line, Treecko line, Braixen, Delphox, and Dragonite.
|
||||
- Added `/transformmodelpart (position|rotation|scale) <modelPart> <transform: x y z>` command that can add transformations to a pokemon's model part.
|
||||
- The player executing the command must be facing the target pokemon entity. Transformations are not persistent and will revert when resources are reloaded.
|
||||
- Added lang keys for all moves and abilities up to Generation 9.
|
||||
- Fixed Moon Ball moon phase logic to actually work correctly
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
@@ -76,6 +78,8 @@
|
||||
- Sneasler
|
||||
- Braixen
|
||||
- Delphox
|
||||
- Cinderace
|
||||
- Kangaskhan
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Gyarados
|
||||
@@ -97,18 +101,32 @@
|
||||
- Pidgeot
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Kangaskhan
|
||||
- Cinderace
|
||||
- Magnezone
|
||||
- Metagross
|
||||
- Added Syrupy Apples.
|
||||
|
||||
### Changes
|
||||
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
|
||||
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
|
||||
- Players can now eat Sweet and Tart Apples, Whipped Dreams, and the Alcremie Sweets.
|
||||
- Updated Sweet and Tart Apple sprites
|
||||
- Updated the following recipes: Air Balloon, Assault Vest, Binding Band, Black Belt, Blunder Policy, Choice Band, Choice Scarf, Cleanse Tag, Covert Cloak, Destiny Knot, Eject Button, Expert Belt, Focus Band, Focus Sash, Magnet, Metronome, Muscle Band, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Protein, Punching Glove, Reaper Cloth, Rocky Helmet, Room Service, Sachet, Safety Goggles, Silk Scarf, Spell Tag, Utility Umbrella, Weakness Policy, Zinc
|
||||
- Added alternate ingredient options to the following recipes: Cell Battery, Charcoal Stick, Dragon Fang, Miracle Seed, Mystic Water, Never Melt Ice, Twisted Spoon, Damp Rock, Heat Rock, Icy Rock, Smooth Rock
|
||||
- Grouped together some recipes within the Recipe Book. Groups include: the seven basic Poké Balls, the seven basic Ancient Poké Balls, Gilded Chests, Pokedexes, and the Weather Rocks.
|
||||
- Updated some item tags to better integrate behaviours between Cobblemon, Vanilla Minecraft, and other mods
|
||||
- Removed Cooked Meat, Raw Meat, Protein Ingredients, and Zinc Ingredients, the first two are now using `c` namespace tags, the latter have better integrated use of tags within their recipes which removes need for custom tags.
|
||||
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
|
||||
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
|
||||
- Substantially optimised spawning checks mainly by front-loading biome filtering.
|
||||
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
|
||||
- Improved the performance of saving Pokédex and player data.
|
||||
- Pokémon hitbox now scales with entity attribute `generic.scale`.
|
||||
- Removed Shulker aspect and replaced it with cosmetic_item-shulker_shell.
|
||||
- Shulker shell Forretress is now a cosmetic rather than a special evo and thus all shulker Forretress will revert back to normal until a shulker shell is put in their cosmetic slot.
|
||||
- Updated `doPokemonSpawning` gamerule to support per-dimension configurations.
|
||||
- The Pokedex now displays a form name of a "normal" Pokémon for when the base form is still a named form.
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
@@ -137,6 +155,7 @@
|
||||
- Fixed Pokémon marked as silent still playing shiny sounds and effects.
|
||||
- Fixed an issue with newer versions of Fabric API where underground Pokémon were spawning in The End.
|
||||
- Fixed spawning not working well when you're at high points surrounded by lower altitude spawning areas, such as flying.
|
||||
- Fixed certain Pokémon with forms not having appropriate stock Pokédex entries.
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -173,6 +192,7 @@
|
||||
- Added `pokemon` as an available Molang function for the `battleActor` functions.
|
||||
- Fixed `heldItem` property inside spawn files not working and causing crashes
|
||||
- Fixed `spawn_bedrock_particles` MoLang causing crashes when used in a server environment
|
||||
- The Pokédex form lang key definition now follows `cobblemon.ui.pokedex.info.form.{species}-{formname}` instead of `cobblemon.ui.pokedex.info.form.{formname}`.
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
|
||||
@@ -8,11 +8,24 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
|
||||
import com.cobblemon.mod.common.stadium.StadiumClientManager;
|
||||
import com.cobblemon.mod.common.util.CameraExtensionsKt;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -20,6 +33,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public class GameRendererMixin {
|
||||
@Shadow @Final Minecraft minecraft;
|
||||
@Shadow float renderDistance;
|
||||
@Shadow @Final private LightTexture lightTexture;
|
||||
@Shadow private boolean renderHand;
|
||||
|
||||
@Shadow private double getFov(Camera activeRenderInfo, float partialTicks, boolean useFOVSetting) { return 0.0; }
|
||||
@Shadow public void resetProjectionMatrix(Matrix4f matrix) {}
|
||||
@Shadow public Matrix4f getProjectionMatrix(double fov) { return new Matrix4f(); }
|
||||
@Shadow private void renderItemInHand(Camera camera, float partialTick, Matrix4f projectionMatrix) {}
|
||||
@Shadow public void pick(float partialTicks) {}
|
||||
|
||||
@Unique
|
||||
long lastTime = -1;
|
||||
|
||||
@@ -42,4 +66,54 @@ public class GameRendererMixin {
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
@Inject(method = "renderLevel", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void renderLevel(DeltaTracker deltaTracker, CallbackInfo ci) {
|
||||
if (StadiumClientManager.INSTANCE.shouldUseStadiumCamera()) {
|
||||
float f = deltaTracker.getGameTimeDeltaPartialTick(true);
|
||||
this.lightTexture.updateLightTexture(f);
|
||||
if (this.minecraft.getCameraEntity() == null) {
|
||||
this.minecraft.setCameraEntity(this.minecraft.player);
|
||||
}
|
||||
|
||||
this.minecraft.getProfiler().push("camera");
|
||||
Camera stadiumCamera = new Camera();
|
||||
Entity entity = (Entity) this.minecraft.player;
|
||||
stadiumCamera.setup(this.minecraft.level, entity, false, false, 1.0F);
|
||||
|
||||
//adjust camera
|
||||
StadiumClientManager.INSTANCE.updateCameraData(f);
|
||||
var position = StadiumClientManager.INSTANCE.getCameraPosition();
|
||||
stadiumCamera.setPosition(position);
|
||||
|
||||
Quaternionf rotation = StadiumClientManager.INSTANCE.getCameraRotation();
|
||||
var forwardVector = rotation.transform(Camera.FORWARDS, new Vector3f());
|
||||
var upVector = rotation.transform(Camera.UP, new Vector3f());
|
||||
var leftVector = rotation.transform(Camera.LEFT, new Vector3f());
|
||||
stadiumCamera.rotation.set(rotation);
|
||||
stadiumCamera.xRot = (float)Mth.wrapDegrees(-Math.toDegrees(Math.asin(forwardVector.y)));
|
||||
stadiumCamera.yRot = Mth.wrapDegrees((float)-Math.toDegrees(Camera.FORWARDS.angleSigned(forwardVector, Camera.UP)) + 180);
|
||||
stadiumCamera.forwards.set(forwardVector);
|
||||
stadiumCamera.up.set(upVector);
|
||||
stadiumCamera.left.set(leftVector);
|
||||
|
||||
this.renderDistance = (float)(this.minecraft.options.getEffectiveRenderDistance() * 16);
|
||||
double d = this.getFov(stadiumCamera, f, true);
|
||||
Matrix4f matrix4f = this.getProjectionMatrix(d);
|
||||
|
||||
this.resetProjectionMatrix(matrix4f);
|
||||
Quaternionf quaternionf = stadiumCamera.rotation().conjugate(new Quaternionf());
|
||||
Matrix4f matrix4f2 = (new Matrix4f()).rotation(quaternionf);
|
||||
this.minecraft.levelRenderer.prepareCullFrustum(stadiumCamera.getPosition(), matrix4f2, this.getProjectionMatrix(Math.max(d, (double)(Integer)this.minecraft.options.fov().get())));
|
||||
this.minecraft.levelRenderer.renderLevel(deltaTracker, false, stadiumCamera, (GameRenderer) (Object) this, this.lightTexture, matrix4f2, matrix4f);
|
||||
|
||||
this.minecraft.getProfiler().pop();
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "TAIL"))
|
||||
public void tick(CallbackInfo ci) {
|
||||
// StadiumClientManager.INSTANCE.tickCameraManager();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,21 @@ public class HumanoidModelMixin {
|
||||
}
|
||||
|
||||
Entity vehicle = entity.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity && entity instanceof AbstractClientPlayer) {
|
||||
MountedPlayerRenderer.INSTANCE.animate((PokemonEntity) vehicle, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity && entity instanceof AbstractClientPlayer) {
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRotatePlayerHead(settings, state, pokemonEntity);
|
||||
});
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
if (this.head != null) {
|
||||
this.head.yRot = 0f;
|
||||
this.head.xRot = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
MountedPlayerRenderer.INSTANCE.animate(pokemonEntity, (AbstractClientPlayer) entity, relevantPartsByName, netHeadYaw, headPitch, ageInTicks, limbSwing, limbSwingAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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(PlayerModel.class)
|
||||
public class PlayerModelMixin {
|
||||
@Inject(method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V", at = @At(value = "HEAD"))
|
||||
private void cobblemon$setHeadRotation(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci) {
|
||||
if (!(entity instanceof Player)) return;
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity pokemonEntity)) return;
|
||||
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRotatePlayerHead(settings, state, pokemonEntity);
|
||||
});
|
||||
if (shouldRotatePlayerHead) return;
|
||||
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
@JvmField
|
||||
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.of(::PCBlockEntity, CobblemonBlocks.PC).build(null))
|
||||
|
||||
@JvmField
|
||||
val STADIUM: BlockEntityType<StadiumBlockEntity> = this.create("stadium_terminal", BlockEntityType.Builder.of(::StadiumBlockEntity, CobblemonBlocks.STADIUM).build(null))
|
||||
|
||||
@JvmField
|
||||
val LECTERN: BlockEntityType<LecternBlockEntity> = this.create("lectern", BlockEntityType.Builder.of(::LecternBlockEntity, CobblemonBlocks.LECTERN).build(null))
|
||||
|
||||
|
||||
@@ -354,6 +354,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }))
|
||||
|
||||
@JvmField
|
||||
val STADIUM = create("stadium_terminal", StadiumBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F)))
|
||||
|
||||
@JvmField
|
||||
val LECTERN = create("lectern", LecternBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).sound(SoundType.WOOD).strength(2.5F).ignitedByLava()))
|
||||
|
||||
|
||||
@@ -272,6 +272,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val PC = blockItem("pc", CobblemonBlocks.PC)
|
||||
@JvmField
|
||||
val STADIUM = blockItem("stadium_terminal", CobblemonBlocks.STADIUM)
|
||||
@JvmField
|
||||
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
|
||||
@JvmField
|
||||
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
|
||||
@@ -293,20 +295,21 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
|
||||
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
|
||||
@JvmField val SACHET = noSettingsItem("sachet")
|
||||
@JvmField val WHIPPED_DREAM = noSettingsItem("whipped_dream")
|
||||
@JvmField val STRAWBERRY_SWEET = noSettingsItem("strawberry_sweet")
|
||||
@JvmField val LOVE_SWEET = noSettingsItem("love_sweet")
|
||||
@JvmField val BERRY_SWEET = noSettingsItem("berry_sweet")
|
||||
@JvmField val CLOVER_SWEET = noSettingsItem("clover_sweet")
|
||||
@JvmField val FLOWER_SWEET = noSettingsItem("flower_sweet")
|
||||
@JvmField val STAR_SWEET = noSettingsItem("star_sweet")
|
||||
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
|
||||
@JvmField val WHIPPED_DREAM = create("whipped_dream", foodItem(8, 0.3f))
|
||||
@JvmField val STRAWBERRY_SWEET = create("strawberry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val LOVE_SWEET = create("love_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val BERRY_SWEET = create("berry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CLOVER_SWEET = create("clover_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val FLOWER_SWEET = create("flower_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val STAR_SWEET = create("star_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val RIBBON_SWEET = create("ribbon_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
|
||||
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
|
||||
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
|
||||
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
|
||||
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
|
||||
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
|
||||
@JvmField val SWEET_APPLE = create("sweet_apple", foodItem(4, 0.3f))
|
||||
@JvmField val TART_APPLE = create("tart_apple", foodItem(4, 0.3f))
|
||||
@JvmField val SYRUPY_APPLE = create("syrupy_apple", foodItem(4, 0.3f))
|
||||
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
|
||||
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
|
||||
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
|
||||
@@ -1358,4 +1361,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return createdItem
|
||||
}
|
||||
|
||||
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
|
||||
return Item(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
|
||||
}
|
||||
}
|
||||
@@ -218,6 +218,10 @@ import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHa
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
|
||||
import com.cobblemon.mod.common.stadium.StadiumCamerasSyncPacket
|
||||
import com.cobblemon.mod.common.stadium.StadiumJoinHandler
|
||||
import com.cobblemon.mod.common.stadium.StadiumJoinPacket
|
||||
import com.cobblemon.mod.common.stadium.StadiumCameraManagersSyncPacket
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
@@ -374,6 +378,8 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(StadiumCamerasSyncPacket.ID, StadiumCamerasSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(StadiumCameraManagersSyncPacket.ID, StadiumCameraManagersSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
// Effects
|
||||
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
|
||||
@@ -436,6 +442,9 @@ object CobblemonNetwork {
|
||||
// Riding
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
|
||||
|
||||
// Stadium packets
|
||||
list.add(PacketRegisterInfo(StadiumJoinPacket.ID, StadiumJoinPacket::decode, StadiumJoinHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
|
||||
@@ -832,6 +832,7 @@ object MoLangFunctions {
|
||||
map.put("is_moving") { DoubleValue((pokemonEntity.moveControl as? PokemonMoveControl)?.hasWanted() == true) }
|
||||
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
|
||||
map.put("is_gliding") { DoubleValue(pokemonEntity.useRidingAltPose()) }
|
||||
map.put("is_ridden") { DoubleValue(pokemonEntity.hasControllingPassenger()) }
|
||||
map.put("has_aspect") { DoubleValue(it.getString(0) in pokemonEntity.aspects) }
|
||||
map.put("is_pokemon") { DoubleValue.ONE }
|
||||
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).let {
|
||||
|
||||
+18
@@ -107,4 +107,22 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
val roll: Float
|
||||
get() = Mth.wrapDegrees(-upVector.angleSigned(UP, forwardVector).toDegrees())
|
||||
|
||||
fun applyGlobalYaw(deltaYawDegrees: Float) = updateOrientation { original ->
|
||||
val euler = Vector3f()
|
||||
original.getEulerAnglesXYZ(euler)
|
||||
val pitch0 = euler.x
|
||||
val roll0 = euler.z
|
||||
|
||||
val unroll = Matrix3f().rotateZ(-roll0)
|
||||
val unpitch = Matrix3f().rotateX(-pitch0)
|
||||
val flattened = Matrix3f(original).mul(unroll).mul(unpitch)
|
||||
|
||||
//Flip to reflect current acceptance of what direction is pos for yaw
|
||||
val globalYaw = Matrix3f().rotationY(-1.0f * deltaYawDegrees.toRadians())
|
||||
val rePitch = Matrix3f().rotateX(pitch0)
|
||||
val reRoll = Matrix3f().rotateZ(roll0)
|
||||
|
||||
return@updateOrientation Matrix3f(globalYaw).mul(flattened).mul(rePitch).mul(reRoll)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-6
@@ -77,18 +77,18 @@ object CatchRateModifiers {
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.MOON_BALL].
|
||||
* Boosts the catch rate 1.5× during Moon Phases 3 and 7 between the times of 12000 – 24000.
|
||||
* 2.5× during Moon Phases 2 and 8 between the times of 12000 – 24000.
|
||||
* 4× during Moon Phase 1 between the times of 12000 – 24000.
|
||||
* Boosts the catch rate 1.5× during Moon Phases 2 and 6 between the times of 12000 – 24000.
|
||||
* 2.5× during Moon Phases 1 and 7 between the times of 12000 – 24000.
|
||||
* 4× during Moon Phase 0 between the times of 12000 – 24000.
|
||||
* 1× otherwise.
|
||||
*/
|
||||
val MOON_PHASES: CatchRateModifier = WorldStateModifier { _, entity ->
|
||||
if (entity.level().gameTime in 12000..24000)
|
||||
return@WorldStateModifier 1F
|
||||
when (entity.level().moonPhase) {
|
||||
3, 7 -> 1.5F
|
||||
2, 8 -> 2.5F
|
||||
1 -> 4F
|
||||
2, 6 -> 1.5F
|
||||
1, 7 -> 2.5F
|
||||
0 -> 4F
|
||||
else -> 1F
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -24,11 +24,11 @@ import net.minecraft.world.phys.Vec3
|
||||
*/
|
||||
open class RidingBehaviourState {
|
||||
open val rideVelocity: SidedRidingState<Vec3> = ridingState(Vec3.ZERO, Side.BOTH)
|
||||
open val stamina: SidedRidingState<Float> = ridingState(0F, Side.BOTH)
|
||||
open val stamina: SidedRidingState<Float> = ridingState(1.0F, Side.BOTH)
|
||||
|
||||
open fun reset() {
|
||||
rideVelocity.set(Vec3.ZERO, true)
|
||||
stamina.set(0F, true)
|
||||
stamina.set(1.0F, true)
|
||||
}
|
||||
|
||||
open fun copy(): RidingBehaviourState {
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ object RidingBehaviours {
|
||||
register(JetAirBehaviour.KEY, JetAirBehaviour())
|
||||
register(SwimDashBehaviour.KEY, SwimDashBehaviour())
|
||||
register(VehicleLandBehaviour.KEY, VehicleLandBehaviour())
|
||||
register(HoverBehaviour.KEY, HoverBehaviour())
|
||||
register(CompositeBehaviour.KEY, CompositeBehaviour())
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -41,6 +41,11 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
|
||||
return behaviour.speed(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity) {
|
||||
if (!isActive(settings, state, vehicle)) return
|
||||
return behaviour.clampPassengerRotation(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun rotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
if (!isActive(settings, state, vehicle)) return driver.rotationVector
|
||||
return behaviour.rotation(settings, state, vehicle, driver)
|
||||
|
||||
+81
-37
@@ -27,6 +27,9 @@ 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.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
@@ -179,26 +182,26 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
//Lateral movement based on driver input.
|
||||
val latTopSpeed = topSpeed / 2.0
|
||||
if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
|
||||
newVelocity = Vec3(
|
||||
(newVelocity.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
|
||||
newVelocity.y,
|
||||
newVelocity.z)
|
||||
activeInput = true
|
||||
}
|
||||
else {
|
||||
newVelocity = Vec3(
|
||||
lerp(newVelocity.x, 0.0, latTopSpeed / 20.0),
|
||||
newVelocity.y,
|
||||
newVelocity.z)
|
||||
}
|
||||
// val latTopSpeed = topSpeed / 2.0
|
||||
// if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
|
||||
// newVelocity = Vec3(
|
||||
// (newVelocity.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
|
||||
// newVelocity.y,
|
||||
// newVelocity.z)
|
||||
// activeInput = true
|
||||
// }
|
||||
// else {
|
||||
// newVelocity = Vec3(
|
||||
// lerp(newVelocity.x, 0.0, latTopSpeed / 20.0),
|
||||
// newVelocity.y,
|
||||
// newVelocity.z)
|
||||
// }
|
||||
|
||||
//Vertical movement based on driver input.
|
||||
val vertTopSpeed = topSpeed / 2.0
|
||||
val vertInput = when {
|
||||
driver.jumping -> 1.0
|
||||
driver.isShiftKeyDown -> -1.0
|
||||
driver.jumping && state.rideVelocity.get().length() < 0.3 -> 1.0
|
||||
driver.isShiftKeyDown && state.rideVelocity.get().length() < 0.3 -> -1.0
|
||||
else -> 0.0
|
||||
}
|
||||
|
||||
@@ -225,23 +228,24 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
}
|
||||
|
||||
//Only perform stamina logic if the ride does not have infinite stamina
|
||||
if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
|
||||
if (activeInput) {
|
||||
state.stamina.set(state.stamina.get() - (0.05 / staminaStat).toFloat())
|
||||
}
|
||||
|
||||
//Lose a base amount of stamina just for being airborne
|
||||
state.stamina.set(state.stamina.get() - (0.01 / staminaStat).toFloat())
|
||||
}
|
||||
else
|
||||
{
|
||||
state.stamina.set(1.0f)
|
||||
}
|
||||
//TODO: Reintroduce stamina drain once stats start to be polished and tweaked
|
||||
// //Only perform stamina logic if the ride does not have infinite stamina
|
||||
// if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
|
||||
// if (activeInput) {
|
||||
// state.stamina.set(state.stamina.get() - (0.05 / staminaStat).toFloat())
|
||||
// }
|
||||
//
|
||||
// //Lose a base amount of stamina just for being airborne
|
||||
// state.stamina.set(state.stamina.get() - (0.01 / staminaStat).toFloat())
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// state.stamina.set(1.0f)
|
||||
// }
|
||||
|
||||
//air resistance
|
||||
if( abs(newVelocity.z) > 0) {
|
||||
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.003 * newVelocity.z.sign, newVelocity.z))
|
||||
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.0015 * newVelocity.z.sign, newVelocity.z))
|
||||
}
|
||||
state.rideVelocity.set(newVelocity)
|
||||
}
|
||||
@@ -256,10 +260,17 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
//TODO: Tie into handling
|
||||
//limit rolling based on handling and current speed.
|
||||
//modulated by speed so that when flapping idle in air you are ont wobbling around to look around
|
||||
//TODO: Tie handling into yaw rate
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val rotationChangeRate = 10.0
|
||||
//This rotation limit will be used to know if the ride has exceeded it and its needs correcting.
|
||||
val rotMin = 15.0
|
||||
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
|
||||
|
||||
|
||||
val rotationChangeRate = 100.0
|
||||
|
||||
var yawForce = rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble()))
|
||||
//for a bit of correction on the rolls limit it to a quarter the amount
|
||||
@@ -269,7 +280,28 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
yawForce *= abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
pitchForce *= abs(cos(Math.toRadians(controller.pitch.toDouble()))) * 1.5
|
||||
|
||||
return Vec3(yawForce, pitchForce, 0.0)
|
||||
var yawDeltaDeg = deltaTime * rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble())) //sin(Math.toRadians(controller.roll.toDouble())) * abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
//val pitchedYawDelt = yawDeltaDeg - trueYawDelt
|
||||
|
||||
controller.applyGlobalYaw(trueYawDelt.toFloat())
|
||||
|
||||
val correctionRate = 5.0
|
||||
//Calculate correcting roll force.
|
||||
if(abs(controller.roll) > rotLimit) {
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + ((abs(controller.roll) - rotLimit) / 180 - rotLimit) * controller.roll.sign * correctionRate * deltaTime * 0.01
|
||||
)
|
||||
} else {
|
||||
state.currRollCorrectionForce.set(
|
||||
//reduce rollCorrection gradually and make sure to
|
||||
//state.currRollCorrectionForce.get() - max(correctionRate * deltaTime * 0.04, abs(state.currRollCorrectionForce.get())) * state.currRollCorrectionForce.get().sign
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
)
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, 0.0, state.currRollCorrectionForce.get())
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
@@ -303,13 +335,14 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
//modulated by speed so that when flapping idle in air you are ont wobbling around to look around
|
||||
val rotMin = 15.0
|
||||
var rollForce = xInput
|
||||
val rotLimit = max(handling * normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).pow(3), rotMin)
|
||||
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
|
||||
|
||||
//Limit roll by non linearly decreasing inputs towards
|
||||
// a rotation limit based on the current distance from
|
||||
// that rotation limit
|
||||
if (abs(controller.roll + rollForce) < rotLimit) {
|
||||
if (sign(rollForce) == sign(controller.roll).toDouble()) {
|
||||
//Grab how far the current roll is away from the roll limit
|
||||
val d = abs(abs(controller.roll) - rotLimit)
|
||||
rollForce *= (d.pow(2)) / (rotLimit.pow(2))
|
||||
}
|
||||
@@ -318,10 +351,18 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * ( 1.0 - normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).pow(3))
|
||||
val yawForce = xInput * ( 1.0 - sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)))
|
||||
|
||||
//Yaw locally a bit when up or down so that its more intuitive to make it out of a dive or a straight vertical
|
||||
//climb
|
||||
val yawForcePitched = xInput * sin(Math.toRadians(abs(controller.pitch.toDouble()))) * 0.25
|
||||
|
||||
|
||||
//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())
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(yawForce, yInput, rollForce)
|
||||
return Vec3(yawForcePitched, yInput, rollForce)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -486,6 +527,7 @@ class BirdAirSettings : RidingBehaviourSettings {
|
||||
class BirdAirState : RidingBehaviourState() {
|
||||
var gliding = ridingState(false, Side.CLIENT)
|
||||
var lastGlide = ridingState(-100L, Side.CLIENT)
|
||||
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
@@ -502,6 +544,7 @@ class BirdAirState : RidingBehaviourState() {
|
||||
super.reset()
|
||||
gliding.set(false, forced = true)
|
||||
lastGlide.set(-100L, forced = true)
|
||||
currRollCorrectionForce.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
@@ -513,11 +556,12 @@ class BirdAirState : RidingBehaviourState() {
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
it.gliding.set(this.gliding.get(), forced = true)
|
||||
it.lastGlide.set(this.lastGlide.get(), forced = true)
|
||||
it.currRollCorrectionForce.set(this.currRollCorrectionForce.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is BirdAirState) return false
|
||||
if (previous.gliding != gliding) return true
|
||||
if (previous.gliding.get() != gliding.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
|
||||
+149
-79
@@ -9,7 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
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
|
||||
@@ -18,15 +18,14 @@ import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.*
|
||||
|
||||
class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandState> {
|
||||
companion object {
|
||||
@@ -38,7 +37,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
|
||||
val poseProvider = PoseProvider<GenericLandSettings, GenericLandState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption state.rideVelocity.get().z > 0.1
|
||||
return@PoseOption abs(state.rideVelocity.get().z) > 0.2
|
||||
})
|
||||
|
||||
override fun isActive(
|
||||
@@ -77,15 +76,99 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
|
||||
//Take the inverse so that it cancels out how
|
||||
//much the entity rotates.
|
||||
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
|
||||
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
val rotMod = Mth.wrapDegrees(driver.yRot - vehicle.yRot) / maxYawDiff
|
||||
|
||||
val rotAmount = 10.0f
|
||||
|
||||
//Take the inverse so that you turn more at higher speeds
|
||||
val normSpeed = 1.0f - 0.5f*normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
//driver.yRot += (entity.riding.deltaRotation.y - turnAmount)
|
||||
//driver.setYHeadRot(driver.yHeadRot + (entity.riding.deltaRotation.y) - turnAmount)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
val f = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
|
||||
val lookYawLimit = 90.0f
|
||||
val g = Mth.clamp(f, -lookYawLimit, lookYawLimit)
|
||||
driver.yRotO += g - f
|
||||
driver.yRot = driver.yRot + g - f
|
||||
driver.setYHeadRot(driver.yRot)
|
||||
}
|
||||
|
||||
|
||||
override fun rotation(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
|
||||
|
||||
return Vec2(vehicle.xRot, vehicle.yRot + turnAmount )
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the rotation amount given the difference between
|
||||
* the current player y rot and entity y rot. This gives the
|
||||
* affect of influencing a rides rotation through the mouse
|
||||
* without it being instant.
|
||||
*/
|
||||
fun calcRotAmount(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
//In degrees per second
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
val rotDiff = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
|
||||
val rotDiffNorm = rotDiff / maxYawDiff
|
||||
|
||||
//Take the square root so that the ride levels out quicker when at lower differences between entity
|
||||
//y and driver y
|
||||
//This influences the speed of the turn based on how far in one direction you're looking
|
||||
val rotDiffMod = (sqrt(abs(rotDiffNorm)) * rotDiffNorm.sign)
|
||||
|
||||
//Take the inverse so that you turn less at higher speeds
|
||||
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
// TODO: This needs to be tweaked with in game results and testing
|
||||
val turnRate = (handling.toFloat() / 20.0f) * 2
|
||||
|
||||
//Ensure you only ever rotate as much difference as there is between the angles.
|
||||
val turnSpeed = turnRate * rotDiffMod * normSpeed
|
||||
val rotAmount = turnSpeed.coerceIn(-abs(rotDiff), abs(rotDiff))
|
||||
|
||||
return rotAmount
|
||||
}
|
||||
|
||||
|
||||
override fun velocity(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
@@ -93,24 +176,16 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
val driveFactor = runtime.resolveFloat(settings.driveFactor)
|
||||
val strafeFactor = runtime.resolveFloat(settings.strafeFactor)
|
||||
val f = driver.xxa * strafeFactor
|
||||
var g = driver.zza * driveFactor
|
||||
if (g <= 0.0f) {
|
||||
g *= runtime.resolveFloat(settings.reverseDriveFactor)
|
||||
}
|
||||
val gravity = -1.0
|
||||
//Limit horizontal velocity that may have accumulated through alternate behaviour
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val currVel = state.rideVelocity.get()
|
||||
// state.rideVelocity.set(Vec3(
|
||||
// max(currVel.x, topSpeed),
|
||||
// currVel.y,
|
||||
// max(currVel.z, topSpeed)
|
||||
// ))
|
||||
|
||||
val newVelocity = calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
|
||||
//Jump the thang!
|
||||
if (driver.jumping && vehicle.onGround()) {
|
||||
state.rideVelocity.set(Vec3(newVelocity.x, 2.0, newVelocity.z))
|
||||
} else {
|
||||
state.rideVelocity.set(newVelocity)
|
||||
}
|
||||
state.rideVelocity.set(calculateRideSpaceVel(settings, state, vehicle, driver))
|
||||
|
||||
//This is cheap.
|
||||
//Also make it stop quicker the slower it is.
|
||||
@@ -129,35 +204,59 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.topSpeedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val speed = state.rideVelocity.get().length()
|
||||
|
||||
val minSpeed = 0.0
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.get().z)
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza > 0.0 && speed <= topSpeed && state.stamina.get() > 0.0f) {
|
||||
//modify acceleration to be slower when at closer speeds to top speed
|
||||
val accelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2), 0.1)
|
||||
newVelocity = Vec3(newVelocity.x, newVelocity.y, min(newVelocity.z + (accel * accelMod), topSpeed))
|
||||
} else if (driver.zza >= 0.0 && state.stamina.get() == 0.0f || speed > topSpeed) {
|
||||
newVelocity = Vec3(newVelocity.x, newVelocity.y, max(newVelocity.z - ((accel) / 4), minSpeed))
|
||||
} else if (driver.zza < 0.0 && speed > minSpeed) {
|
||||
//modify deccel to be slower when at closer speeds to minimum speed
|
||||
val deccelMod = max(-(normalizeSpeed(speed, minSpeed, topSpeed)) + 1, 0.0)
|
||||
|
||||
//Decelerate currently always a constant half of max acceleration.
|
||||
newVelocity =
|
||||
Vec3(newVelocity.x, newVelocity.y, max(newVelocity.z - ((accel * deccelMod) / 2), minSpeed))
|
||||
//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 {
|
||||
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
//Gravity logic
|
||||
if (vehicle.onGround()) {
|
||||
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z)
|
||||
} else {
|
||||
newVelocity = Vec3(newVelocity.x, max(newVelocity.y - 0.2, -1.0), newVelocity.z)
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2
|
||||
val terminalVel = 2.0
|
||||
|
||||
val fallingForce = gravity - ( newVelocity.z.sign *gravity *(abs(newVelocity.z) / 2.0))
|
||||
newVelocity = Vec3(newVelocity.x, max(newVelocity.y - fallingForce, -terminalVel), newVelocity.z)
|
||||
}
|
||||
|
||||
//ground Friction
|
||||
if( abs(newVelocity.z) > 0 && vehicle.onGround() && !activeInput) {
|
||||
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.03 * newVelocity.z.sign, newVelocity.z))
|
||||
}
|
||||
|
||||
//Jump the thang!
|
||||
if (driver.jumping && vehicle.onGround()) {
|
||||
val jumpVel = 1.0
|
||||
newVelocity = newVelocity.add(0.0, 1.0, 0.0)
|
||||
|
||||
//Ensure this doesn't add unwanted forward velocity
|
||||
val mag = if(newVelocity.length() < topSpeed) newVelocity.length() else topSpeed
|
||||
newVelocity = newVelocity.normalize().scale(mag)
|
||||
}
|
||||
|
||||
return newVelocity
|
||||
}
|
||||
|
||||
@@ -165,7 +264,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
* Normalizes the current speed between minSpeed and maxSpeed.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents minSpeed and 1.0 represents maxSpeed.
|
||||
*/
|
||||
private fun normalizeSpeed(currSpeed: Double, minSpeed: Double, maxSpeed: Double): Double {
|
||||
private fun normalizeVal(currSpeed: Double, minSpeed: Double, maxSpeed: Double): Double {
|
||||
require(maxSpeed > minSpeed) { "maxSpeed must be greater than minSpeed" }
|
||||
return ((currSpeed - minSpeed) / (maxSpeed - minSpeed)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
@@ -217,8 +316,6 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
driver: Player
|
||||
): Float {
|
||||
//Retrieve stamina from state and tick up at a rate of 0.1 a second
|
||||
val staminaGain = (1.0 / 20.0) * 0.1
|
||||
state.stamina.set(min(state.stamina.get() + staminaGain, 1.0).toFloat())
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
@@ -229,10 +326,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
|
||||
val jumpVector = settings.jumpVector.map { runtime.resolveFloat(it) }
|
||||
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
@@ -324,24 +418,15 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
class GenericLandSettings : RidingBehaviourSettings {
|
||||
override val key = GenericLandBehaviour.KEY
|
||||
|
||||
var driveFactor = "1.0".asExpression()
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var topSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.0, 0.3)".asExpression()
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 1.0, 0.3)".asExpression()
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
@@ -357,30 +442,16 @@ class GenericLandSettings : RidingBehaviourSettings {
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeExpression(driveFactor)
|
||||
buffer.writeExpression(strafeFactor)
|
||||
buffer.writeExpression(reverseDriveFactor)
|
||||
buffer.writeExpression(topSpeedExpr)
|
||||
buffer.writeExpression(accelExpr)
|
||||
buffer.writeExpression(jumpVector[0])
|
||||
buffer.writeExpression(jumpVector[1])
|
||||
buffer.writeExpression(jumpVector[2])
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
driveFactor = buffer.readExpression()
|
||||
strafeFactor = buffer.readExpression()
|
||||
reverseDriveFactor = buffer.readExpression()
|
||||
topSpeedExpr = buffer.readExpression()
|
||||
accelExpr = buffer.readExpression()
|
||||
jumpVector = listOf(
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression()
|
||||
)
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
@@ -394,7 +465,6 @@ class GenericLandState : RidingBehaviourState() {
|
||||
override fun copy() = GenericLandState().also {
|
||||
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
it.currSpeed.set(this.currSpeed.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
|
||||
+479
@@ -0,0 +1,479 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
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.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.*
|
||||
|
||||
class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/hover")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.AIR
|
||||
|
||||
val poseProvider = PoseProvider<HoverSettings, HoverState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption abs(state.rideVelocity.get().z) > 0.2
|
||||
})
|
||||
|
||||
override fun isActive(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
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: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): PoseType {
|
||||
return this.poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
|
||||
//Take the inverse so that it cancels out how
|
||||
//much the entity rotates.
|
||||
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
|
||||
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
val rotMod = Mth.wrapDegrees(driver.yRot - vehicle.yRot) / maxYawDiff
|
||||
|
||||
val rotAmount = 10.0f
|
||||
|
||||
//Take the inverse so that you turn more at higher speeds
|
||||
val normSpeed = 1.0f - 0.5f*normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
//driver.yRot += (entity.riding.deltaRotation.y - turnAmount)
|
||||
//driver.setYHeadRot(driver.yHeadRot + (entity.riding.deltaRotation.y) - turnAmount)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
val f = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
|
||||
val lookYawLimit = 90.0f
|
||||
val g = Mth.clamp(f, -lookYawLimit, lookYawLimit)
|
||||
driver.yRotO += g - f
|
||||
driver.yRot = driver.yRot + g - f
|
||||
driver.setYHeadRot(driver.yRot)
|
||||
}
|
||||
|
||||
|
||||
override fun rotation(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
|
||||
|
||||
return Vec2(driver.xRot, vehicle.yRot + turnAmount )
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the rotation amount given the difference between
|
||||
* the current player y rot and entity y rot. This gives the
|
||||
* affect of influencing a rides rotation through the mouse
|
||||
* without it being instant.
|
||||
*/
|
||||
fun calcRotAmount(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
//In degrees per second
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
val rotDiff = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
|
||||
val rotDiffNorm = rotDiff / maxYawDiff
|
||||
|
||||
//Take the square root so that the ride levels out quicker when at lower differences between entity
|
||||
//y and driver y
|
||||
//This influences the speed of the turn based on how far in one direction you're looking
|
||||
val rotDiffMod = (sqrt(abs(rotDiffNorm)) * rotDiffNorm.sign)
|
||||
|
||||
//Take the inverse so that you turn less at higher speeds
|
||||
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
// TODO: This needs to be tweaked with in game results and testing
|
||||
val turnRate = (handling.toFloat() / 20.0f) * 2
|
||||
|
||||
//Ensure you only ever rotate as much difference as there is between the angles.
|
||||
val turnSpeed = turnRate * rotDiffMod * normSpeed
|
||||
val rotAmount = turnSpeed.coerceIn(-abs(rotDiff), abs(rotDiff))
|
||||
|
||||
return rotAmount
|
||||
}
|
||||
|
||||
|
||||
override fun velocity(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
|
||||
val strafeFactor = 0.2
|
||||
val f = driver.xxa * strafeFactor
|
||||
var g = driver.zza
|
||||
if (g <= 0.0f) {
|
||||
g *= -1.0f
|
||||
}
|
||||
|
||||
return calculateRideSpaceVel(settings, state, vehicle, driver).scale(10.0)
|
||||
}
|
||||
|
||||
private fun calculateRideSpaceVel(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val speed = state.rideVelocity.get().length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
val minSpeed = 0.0
|
||||
|
||||
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.get().z)
|
||||
|
||||
var jumpVec = Vec3.ZERO
|
||||
|
||||
|
||||
//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 {
|
||||
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
activeInput = true
|
||||
jumpVec = jumpVec.add(0.0, 0.0, forwardInput.toDouble())
|
||||
}
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
driver.xxa > 0 && newVelocity.x > topSpeed -> 0.0
|
||||
driver.xxa < 0 && newVelocity.x < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.xxa.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x + (accel * forwardInput.toDouble()),
|
||||
newVelocity.y,
|
||||
(newVelocity.z ))
|
||||
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
//Vertical movement based on driver input.
|
||||
val vertTopSpeed = topSpeed / 2.0
|
||||
val vertInput = when {
|
||||
driver.jumping -> 1.0
|
||||
driver.isShiftKeyDown -> -1.0
|
||||
else -> 0.0
|
||||
}
|
||||
|
||||
if (vertInput != 0.0 && state.stamina.get() > 0.0) {
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
(newVelocity.y + (accel * vertInput)).coerceIn(-vertTopSpeed, vertTopSpeed),
|
||||
newVelocity.z)
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
|
||||
//air Friction
|
||||
|
||||
|
||||
|
||||
return newVelocity
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalizes the current speed between minSpeed and maxSpeed.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents minSpeed and 1.0 represents maxSpeed.
|
||||
*/
|
||||
private fun normalizeVal(currSpeed: Double, minSpeed: Double, maxSpeed: Double): Double {
|
||||
require(maxSpeed > minSpeed) { "maxSpeed must be greater than minSpeed" }
|
||||
return ((currSpeed - minSpeed) / (maxSpeed - minSpeed)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseX * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseY * 0.1, deltaTime * smoothingSpeed);
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, yInput, xInput)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
//Retrieve stamina from state and use it to set the "stamina bar"
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return 0.05
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: HoverSettings) = HoverState()
|
||||
}
|
||||
|
||||
class HoverSettings : RidingBehaviourSettings {
|
||||
override val key = HoverBehaviour.KEY
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.3)".asExpression()
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 30.0, 10.0)".asExpression()
|
||||
private set
|
||||
|
||||
//Between a one block jump and a ten block jump
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 10.0, 1.0)".asExpression()
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class HoverState : RidingBehaviourState() {
|
||||
|
||||
override fun copy() = HoverState().also {
|
||||
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is HoverState) return false
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
+48
-28
@@ -26,6 +26,7 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.*
|
||||
|
||||
class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
@@ -40,7 +41,18 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.1 })
|
||||
|
||||
override fun isActive(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
//Need to check other fluids
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any false
|
||||
}
|
||||
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
|
||||
if (it.y.toDouble() == (vehicle.position().y)) {
|
||||
val blockState = vehicle.level().getBlockState(it.below())
|
||||
return@any !(!blockState.isAir && blockState.fluidState.isEmpty)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): PoseType {
|
||||
@@ -55,22 +67,24 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
//retrieve minSpeed
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
|
||||
|
||||
//Reduce stamina unless stamina is infinite
|
||||
if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
|
||||
//Calculate stamina loss due to speed
|
||||
//At max speed it will tick down 0.1 a second so the stamina will last ten seconds
|
||||
//There has got to be a better way to express this equation. It interpolates between 0.5 and 1.0
|
||||
var staminaRate = (normalizeSpeed(state.rideVelocity.get().length(), minSpeed, topSpeed))
|
||||
|
||||
//interpolate between 0.25 and 1.0 so that you always have at least a min of 0.25 stam loss
|
||||
staminaRate = 0.25 + (0.75 * staminaRate.pow(3))
|
||||
|
||||
//Calculate stamina loss in seconds achievable at top speed
|
||||
val staminaLoss = staminaRate * (1.0 / (20.0 * staminaStat))
|
||||
state.stamina.set(max(state.stamina.get() - staminaLoss, 0.0).toFloat())
|
||||
} else {
|
||||
state.stamina.set(1.0f)
|
||||
}
|
||||
//TODO: Reintroduce stamina drain once stats start to be polished and tweaked
|
||||
state.stamina.set(1.0f)
|
||||
// //Reduce stamina unless stamina is infinite
|
||||
// if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
|
||||
// //Calculate stamina loss due to speed
|
||||
// //At max speed it will tick down 0.1 a second so the stamina will last ten seconds
|
||||
// //There has got to be a better way to express this equation. It interpolates between 0.5 and 1.0
|
||||
// var staminaRate = (normalizeSpeed(state.rideVelocity.get().length(), minSpeed, topSpeed))
|
||||
//
|
||||
// //interpolate between 0.25 and 1.0 so that you always have at least a min of 0.25 stam loss
|
||||
// staminaRate = 0.25 + (0.75 * staminaRate.pow(3))
|
||||
//
|
||||
// //Calculate stamina loss in seconds achievable at top speed
|
||||
// val staminaLoss = staminaRate * (1.0 / (20.0 * staminaStat))
|
||||
// state.stamina.set(max(state.stamina.get() - staminaLoss, 0.0).toFloat())
|
||||
// } else {
|
||||
// state.stamina.set(1.0f)
|
||||
// }
|
||||
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
@@ -160,7 +174,7 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, max(state.rideVelocity.get().z - ((accel) / 4), minSpeed)))
|
||||
} else if (driver.zza < 0.0 && speed > minSpeed) {
|
||||
//modify deccel to be slower when at closer speeds to minimum speed
|
||||
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2), 0.1)
|
||||
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2) * 8, 0.1)
|
||||
|
||||
//Decelerate currently always a constant half of max acceleration.
|
||||
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, max(state.rideVelocity.get().z - ((accel * deccelMod) / 2), minSpeed)))
|
||||
@@ -212,8 +226,13 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
|
||||
// Accumulate the mouse input
|
||||
state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX * invertRoll)).coerceIn(-1.0, 1.0))
|
||||
// Smooth out and accumulate roll input
|
||||
val smoothingSpeed = 4.0
|
||||
val mouseXc = (mouseX).coerceIn(-60.0, 60.0)
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
|
||||
// Accumulate the y mouse input for pitch
|
||||
//state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX * invertRoll)).coerceIn(-1.0, 1.0))
|
||||
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY * invertPitch)).coerceIn(-1.0, 1.0))
|
||||
|
||||
//Get handling in degrees per second
|
||||
@@ -235,8 +254,9 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
val pitchRot = handling * state.currMouseYForce.get()
|
||||
|
||||
//Roll is 1.5 times as fast as pitch
|
||||
val rollRot = handling * 1.5 * state.currMouseXForce.get()
|
||||
|
||||
//val rollRot = handling * 1.5 * state.currMouseXForce.get()
|
||||
val rollRot = handling * 1.5 * xInput.coerceIn(-1.0,1.0)
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, pitchRot, rollRot)
|
||||
}
|
||||
@@ -345,10 +365,10 @@ class JetAirSettings : RidingBehaviourSettings {
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
|
||||
var minSpeed: Expression = "1.2".asExpression()
|
||||
var minSpeed: Expression = "0.8".asExpression()
|
||||
private set
|
||||
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 25.0, 8.0)".asExpression()
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 50.0, 25.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Make configurable by json
|
||||
@@ -362,7 +382,7 @@ class JetAirSettings : RidingBehaviourSettings {
|
||||
private set
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
|
||||
private set
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.5, 1.0)".asExpression()
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.8, 1.0)".asExpression()
|
||||
private set
|
||||
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.0)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
@@ -399,8 +419,8 @@ class JetAirSettings : RidingBehaviourSettings {
|
||||
|
||||
class JetAirState : RidingBehaviourState() {
|
||||
var currSpeed = ridingState(0.0, Side.CLIENT)
|
||||
var currMouseXForce = ridingState(0.0, Side.BOTH)
|
||||
var currMouseYForce = ridingState(0.0, Side.BOTH)
|
||||
var currMouseXForce = ridingState(0.0, Side.CLIENT)
|
||||
var currMouseYForce = ridingState(0.0, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
@@ -424,8 +444,8 @@ class JetAirState : RidingBehaviourState() {
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.rideVelocity.set(rideVelocity.get(), forced = true)
|
||||
it.currMouseXForce.set(currMouseXForce.get(), forced = true)
|
||||
it.currMouseYForce.set(currMouseYForce.get(), forced = true)
|
||||
// it.currMouseXForce.set(currMouseXForce.get(), forced = true)
|
||||
// it.currMouseYForce.set(currMouseYForce.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
|
||||
+8
@@ -387,6 +387,8 @@ class CompositeState(
|
||||
super.reset()
|
||||
activeController.set(defaultBehaviour, forced = true)
|
||||
lastTransition.set(-100L, forced = true)
|
||||
defaultBehaviourState.reset()
|
||||
alternateBehaviourState.reset()
|
||||
}
|
||||
|
||||
override fun copy(): CompositeState {
|
||||
@@ -402,17 +404,23 @@ class CompositeState(
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is CompositeState) return false
|
||||
if (previous.activeController.get() != activeController.get()) return true
|
||||
if (defaultBehaviourState.shouldSync(previous.defaultBehaviourState)) return true
|
||||
if (alternateBehaviourState.shouldSync(previous.alternateBehaviourState)) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeResourceLocation(activeController.get())
|
||||
defaultBehaviourState.encode(buffer)
|
||||
alternateBehaviourState.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
activeController.set(buffer.readResourceLocation(), forced = true)
|
||||
defaultBehaviourState.decode(buffer)
|
||||
alternateBehaviourState.decode(buffer)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ interface CompositeRidingStrategy<T : CompositeSettings> {
|
||||
) {
|
||||
toState.stamina.set(fromState.stamina.get())
|
||||
toState.rideVelocity.set(fromState.rideVelocity.get())
|
||||
fromState.reset()
|
||||
state.activeController.set(toSettings.key)
|
||||
state.lastTransition.set(vehicle.level().gameTime)
|
||||
val behaviour = RidingBehaviours.get(toSettings.key)
|
||||
|
||||
+3
-1
@@ -46,9 +46,11 @@ object RunStrategy : CompositeRidingStrategy<CompositeSettings> {
|
||||
driver: Player
|
||||
): Boolean {
|
||||
if (state.activeController.get() == defaultSettings.key) return false
|
||||
if (!entity.onGround()) return false
|
||||
if (state.lastTransition.get() + 20 >= entity.level().gameTime) return false
|
||||
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
|
||||
return !driver.isSprinting || defaultBehaviour.isActive(defaultSettings, state.defaultBehaviourState, entity)
|
||||
val ret = defaultBehaviour.isActive(defaultSettings, state.defaultBehaviourState, entity)
|
||||
return ret
|
||||
}
|
||||
|
||||
private fun shouldTransitionToAlternate(
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
/**
|
||||
* Class to handle the updating and containment of ride data used in animation.
|
||||
*
|
||||
* @author Jackowes
|
||||
* @since April 7th, 2025
|
||||
*/
|
||||
|
||||
|
||||
class RidingAnimationData
|
||||
{
|
||||
var prevOrientation: Matrix3f = Matrix3f()
|
||||
var prevRot: Vec3 = Vec3.ZERO
|
||||
var velocitySpring: Vec3Spring = Vec3Spring()
|
||||
var rotSpring: Vec3Spring = Vec3Spring()
|
||||
var rotDeltaSpring: Vec3Spring = Vec3Spring()
|
||||
var localVelocitySpring: Vec3Spring = Vec3Spring()
|
||||
|
||||
fun update(entity: PokemonEntity) {
|
||||
|
||||
var currRot = Vec3.ZERO
|
||||
var angDelta = Vec3.ZERO
|
||||
|
||||
// val stiffness = 90.0
|
||||
// val damping = 18.0
|
||||
val stiffness = 16.0
|
||||
val damping = 8.0
|
||||
|
||||
// Update velocity first
|
||||
val currentVelocity = Vec3(
|
||||
entity.x - entity.xOld,
|
||||
entity.y - entity.yOld,
|
||||
entity.z - entity.zOld
|
||||
)
|
||||
|
||||
val r = entity.ifRidingAvailableSupply(false) { behaviour, settings, state ->
|
||||
behaviour.shouldRoll(settings, state, entity);
|
||||
}
|
||||
if( r ) {
|
||||
//TODO: should this return?
|
||||
val controller = (entity.firstPassenger as? OrientationControllable)?.orientationController ?: return
|
||||
val orientation = controller.orientation ?: Matrix3f()
|
||||
|
||||
val currPitch = controller.pitch
|
||||
val currYaw = controller.yaw
|
||||
val currRoll = controller.roll
|
||||
currRot = Vec3(currPitch.toDouble(), currYaw.toDouble(), currRoll.toDouble())
|
||||
|
||||
val currOrientation = orientation
|
||||
|
||||
/******************************************************
|
||||
* Calculate current 3d euler rotation deltas in the
|
||||
* entities local space
|
||||
*****************************************************/
|
||||
|
||||
// Get current and previous orientation as quaternions
|
||||
val currQuat = Quaternionf().setFromUnnormalized(currOrientation)
|
||||
val prevQuat = Quaternionf().setFromUnnormalized(prevOrientation)
|
||||
|
||||
// Compute deltaQuat = current * inverse(previous)
|
||||
val deltaQuat = Quaternionf(currQuat).mul(Quaternionf(prevQuat).invert())
|
||||
|
||||
// Transform delta into the local space of the current orientation
|
||||
val localDeltaQuat = Quaternionf(currQuat).invert().mul(deltaQuat).mul(currQuat)
|
||||
|
||||
// Convert delta rotation to Euler angles
|
||||
val euler = Vector3f()
|
||||
localDeltaQuat.getEulerAnglesXYZ(euler) // Angles are in radians
|
||||
|
||||
// Convert to degrees
|
||||
val pitchDegrees = Math.toDegrees(euler.x.toDouble()) // Rotation around X axis = pitch
|
||||
val yawDegrees = Math.toDegrees(euler.y.toDouble()) // Rotation around Y axis = yaw
|
||||
val rollDegrees = Math.toDegrees(euler.z.toDouble()) // Rotation around Z axis = roll
|
||||
//Scale rotation delta by 20 to represent degree per second instead of tick
|
||||
angDelta = Vec3(pitchDegrees, yawDegrees, rollDegrees).scale(20.0)
|
||||
|
||||
/******************************************************
|
||||
* Calculate ride local velocity
|
||||
*****************************************************/
|
||||
val velocityWorldF = Vector3f(currentVelocity.x.toFloat(), currentVelocity.y.toFloat(), currentVelocity.z.toFloat())
|
||||
|
||||
val localVelocityF = Matrix3f(orientation).transpose().transform(velocityWorldF)
|
||||
val localVelocity = Vec3(localVelocityF.x.toDouble(), localVelocityF.y.toDouble(), localVelocityF.z.toDouble())
|
||||
|
||||
localVelocitySpring.update(localVelocity, stiffness, damping)
|
||||
|
||||
// Update previous values
|
||||
prevOrientation.set(currOrientation)
|
||||
} else {
|
||||
val currPitch = entity.xRot
|
||||
val currYaw = entity.yRot
|
||||
val currRoll = 0.0f
|
||||
currRot = Vec3(currPitch.toDouble(), currYaw.toDouble(), currRoll.toDouble())
|
||||
|
||||
//Scale rotation delta by 20 to represent degree per second instead of tick
|
||||
angDelta = Vec3(
|
||||
(currRot.x - prevRot.x),
|
||||
Mth.degreesDifference(currRot.y.toFloat(), prevRot.y.toFloat()).toDouble(),
|
||||
Mth.degreesDifference(currRot.z.toFloat(), prevRot.z.toFloat()).toDouble()
|
||||
).scale(20.0)
|
||||
|
||||
/******************************************************
|
||||
* Calculate ride local velocity
|
||||
*****************************************************/
|
||||
val yaw360 = -1.0 * (entity.yRot + 360.0f) % 360.0f
|
||||
val orientationNonRollable = Matrix3f().rotateY(yaw360.toRadians())
|
||||
|
||||
//Convert to Vector3f
|
||||
var velocityWorldF = Vector3f(currentVelocity.x.toFloat(), currentVelocity.y.toFloat(), currentVelocity.z.toFloat())
|
||||
|
||||
val localVelocityF = Matrix3f(orientationNonRollable).transpose().transform(velocityWorldF)
|
||||
val localVelocity = Vec3(localVelocityF.x.toDouble(), localVelocityF.y.toDouble(), localVelocityF.z.toDouble())
|
||||
|
||||
localVelocitySpring.update(localVelocity, stiffness, damping)
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* Update springs
|
||||
*****************************************************/
|
||||
rotDeltaSpring.update(angDelta, stiffness, damping)
|
||||
velocitySpring.update(currentVelocity, stiffness, damping)
|
||||
rotSpring.update(currRot, stiffness, damping)
|
||||
prevRot = currRot
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* A spring-based smoother for Vec3 values, designed for applying damped spring motion to riding data.
|
||||
* Stores the previous and current values, along with a history buffer for lookback-based interpolation.
|
||||
*
|
||||
* @author Jackowes
|
||||
* @since March 27th, 2025
|
||||
*/
|
||||
|
||||
|
||||
class Vec3Spring(
|
||||
var value: Vec3 = Vec3.ZERO,
|
||||
var velocity: Vec3 = Vec3.ZERO
|
||||
) {
|
||||
val history = ArrayDeque<Vec3>()
|
||||
//Hold up to a seconds worth of values
|
||||
val lookBackSize = 20
|
||||
|
||||
fun update(target: Vec3, stiffness: Double, damping: Double) {
|
||||
|
||||
//Hooke's Law f = kx where:
|
||||
//f is force
|
||||
//k is the spring constant or stiffness of this spring
|
||||
//x is the distance from rest and in this case the difference between the most recent
|
||||
//rotation delta ( the target ) and the springs current value for delta rot
|
||||
val force = target.subtract(value).scale(stiffness)
|
||||
|
||||
//Now calculate acceleration and apply damping
|
||||
val accel = force.subtract(velocity.scale(damping))
|
||||
|
||||
velocity = velocity.add(accel.scale(1.0/20.0))
|
||||
value = value.add(velocity.scale(1.0/20.0))
|
||||
|
||||
history.addFirst(value)
|
||||
//Adding one since if we want to check max look back point it needs something to interp with.
|
||||
if( history.size > lookBackSize + 1) {
|
||||
history.removeLast()
|
||||
}
|
||||
}
|
||||
|
||||
fun getInterpolated(partialTick: Double, lookBackTick: Int): Vec3 {
|
||||
if (history.size < 2) {
|
||||
return value // or Vec3.ZERO if you prefer
|
||||
}
|
||||
|
||||
val tick = min(lookBackTick, history.size - 2)
|
||||
var ret = Vec3.ZERO
|
||||
for( i in 0..tick) {
|
||||
val older = history.get(i + 1).scale(1.0)
|
||||
val newer = history.get(i).scale(1.0)
|
||||
ret = ret.add(older.add(newer.subtract(older).scale(partialTick)))
|
||||
}
|
||||
|
||||
return ret.scale(1.0/(tick+1))
|
||||
}
|
||||
}
|
||||
+30
-8
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import java.util.UUID
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
@@ -32,24 +33,45 @@ object CobblemonWorldSpawnerManager : SpawnerManager() {
|
||||
init {
|
||||
PlatformEvents.SERVER_PLAYER_LOGIN.subscribe { this.onPlayerLogin(it.player) }
|
||||
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe { this.onPlayerLogout(it.player) }
|
||||
PlatformEvents.CHANGE_DIMENSION.subscribe { this.onDimensionChange(it.player, it.origin, it.destination) }
|
||||
}
|
||||
|
||||
fun onPlayerLogin(player: ServerPlayer) {
|
||||
// Disables spawning
|
||||
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
|
||||
if (!Cobblemon.config.enableSpawning || player.level().gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
val spawner = PlayerSpawnerFactory.create(this, player)
|
||||
spawnersForPlayers[player.uuid] = spawner
|
||||
registerSpawner(spawner)
|
||||
registerPlayerSpawner(player)
|
||||
}
|
||||
|
||||
fun onPlayerLogout(player: ServerPlayer) {
|
||||
val spawner = spawnersForPlayers[player.uuid]
|
||||
if (spawner != null) {
|
||||
spawnersForPlayers.remove(player.uuid)
|
||||
unregisterSpawner(spawner)
|
||||
unregisterPlayerSpawner(player)
|
||||
}
|
||||
|
||||
fun onDimensionChange(player: ServerPlayer, origin: ServerLevel?, destination: ServerLevel?) {
|
||||
fun getSpawnRule(level: ServerLevel?) = level?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)
|
||||
|
||||
if (!Cobblemon.config.enableSpawning || getSpawnRule(origin) == getSpawnRule(destination)) {
|
||||
return
|
||||
}
|
||||
|
||||
val spawnerAction = if (destination?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
|
||||
::unregisterPlayerSpawner
|
||||
} else {
|
||||
::registerPlayerSpawner
|
||||
}
|
||||
spawnerAction(player)
|
||||
}
|
||||
|
||||
private fun unregisterPlayerSpawner(player: ServerPlayer) {
|
||||
spawnersForPlayers.remove(player.uuid)?.let { unregisterSpawner(it) }
|
||||
}
|
||||
|
||||
private fun registerPlayerSpawner(player: ServerPlayer) {
|
||||
PlayerSpawnerFactory.create(this, player).also {
|
||||
spawnersForPlayers[player.uuid] = it
|
||||
registerSpawner(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,10 +71,15 @@ open class SpawnerManager {
|
||||
|
||||
open fun onServerTick() {
|
||||
// Disables spawning
|
||||
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
|
||||
if (!Cobblemon.config.enableSpawning) {
|
||||
return
|
||||
}
|
||||
influences.removeIf { it.isExpired() }
|
||||
getSpawnersOfType<TickingSpawner>().forEach(TickingSpawner::tick)
|
||||
getSpawnersOfType<TickingSpawner>().forEach {
|
||||
if (it.getCauseEntity()?.level()?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
|
||||
return@forEach
|
||||
}
|
||||
it.tick()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.block
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.block.entity.StadiumBlockEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.BaseEntityBlock
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.level.block.Mirror
|
||||
import net.minecraft.world.level.block.RenderShape
|
||||
import net.minecraft.world.level.block.Rotation
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
|
||||
class StadiumBlock(properties: Properties): BaseEntityBlock(properties) {
|
||||
companion object {
|
||||
val CODEC = simpleCodec(::StadiumBlock)
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any().setValue(HorizontalDirectionalBlock.FACING, Direction.NORTH))
|
||||
}
|
||||
|
||||
override fun codec() = CODEC
|
||||
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
|
||||
return StadiumBlockEntity(pos, state)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(blockPlaceContext: BlockPlaceContext): BlockState {
|
||||
return this.defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, blockPlaceContext.horizontalDirection)
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HorizontalDirectionalBlock.FACING)
|
||||
}
|
||||
|
||||
override fun rotate(blockState: BlockState, rotation: Rotation): BlockState {
|
||||
return blockState.setValue(
|
||||
HorizontalDirectionalBlock.FACING, rotation.rotate(blockState.getValue(
|
||||
HorizontalDirectionalBlock.FACING)))
|
||||
}
|
||||
|
||||
override fun mirror(blockState: BlockState, mirror: Mirror): BlockState {
|
||||
return blockState.rotate(mirror.getRotation(blockState.getValue(HorizontalDirectionalBlock.FACING)))
|
||||
}
|
||||
|
||||
override fun onRemove(state: BlockState, world: Level, pos: BlockPos, newState: BlockState, moved: Boolean) {
|
||||
if (!state.`is`(newState.block)) super.onRemove(state, world, pos, newState, moved)
|
||||
}
|
||||
|
||||
//TODO: override getTicker
|
||||
|
||||
override fun getRenderShape(state: BlockState) = RenderShape.MODEL
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
if (player !is ServerPlayer) return InteractionResult.SUCCESS
|
||||
|
||||
val blockEntity = world.getBlockEntity(pos)
|
||||
if (blockEntity !is StadiumBlockEntity) return InteractionResult.SUCCESS
|
||||
|
||||
player.sendSystemMessage(text("Adding you to Battle").red())
|
||||
blockEntity.addPlayer(player)
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
/*
|
||||
override fun useWithoutItem(
|
||||
blockState: BlockState,
|
||||
world: Level,
|
||||
blockPos: BlockPos,
|
||||
player: Player,
|
||||
blockHitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
if (player !is ServerPlayer) return InteractionResult.SUCCESS
|
||||
|
||||
val blockEntity = world.getBlockEntity(blockPos)
|
||||
if (blockEntity !is StadiumBlockEntity) return InteractionResult.SUCCESS
|
||||
|
||||
// Toggle isInUse state
|
||||
blockEntity.isInUse = !blockEntity.isInUse
|
||||
|
||||
// debug
|
||||
val activateMessage = if (blockEntity.isInUse) "Stadium Activated!" else "Stadium Deactivated!"
|
||||
player.sendSystemMessage(text(activateMessage).red())
|
||||
|
||||
if (blockEntity.isInUse) {
|
||||
// Generate flight path when activated
|
||||
blockEntity.generateFlightPath(world, radiusX = 5.0, radiusZ = 3.0, height = 10.0, steps = 20)
|
||||
|
||||
} else {
|
||||
// Clear path when deactivated
|
||||
blockEntity.pathPoints.clear()
|
||||
}
|
||||
|
||||
val message = "Stadium Pos: " + blockEntity.blockPos +
|
||||
"\nPlayer 1 Pos: " + blockEntity.getPlayer1Pos() +
|
||||
"\nPoke 1 Pos: " + blockEntity.getPoke1Pos() +
|
||||
"\nPlayer 2 Pos: " + blockEntity.getPlayer2Pos() +
|
||||
"\nPoke 2 Pos: " + blockEntity.getPoke2Pos()
|
||||
player.sendSystemMessage(text(message).red())
|
||||
|
||||
blockEntity.setChanged()
|
||||
world.sendBlockUpdated(blockPos, blockState, blockState, Block.UPDATE_CLIENTS)
|
||||
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.cobblemon.mod.common.block.entity
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneState
|
||||
import com.cobblemon.mod.common.stadium.StadiumSingleBattle
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.network.protocol.Packet
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
|
||||
import net.minecraft.network.protocol.game.ClientboundPlayerLookAtPacket
|
||||
import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class StadiumBlockEntity(
|
||||
pos: BlockPos,
|
||||
blockState: BlockState
|
||||
): BlockEntity(
|
||||
CobblemonBlockEntities.STADIUM,
|
||||
pos,
|
||||
blockState
|
||||
) {
|
||||
var storedPlayers = mutableListOf<ServerPlayer>()
|
||||
|
||||
var battleDefenition = StadiumSingleBattle()
|
||||
|
||||
fun addPlayer(player: ServerPlayer) {
|
||||
battleDefenition.addPlayer(player)
|
||||
if (battleDefenition.readyForBattle()) battleDefenition.initializeBattle()
|
||||
}
|
||||
|
||||
/*
|
||||
var isInUse = false
|
||||
|
||||
val droneState = DroneState()
|
||||
|
||||
val pathPoints: MutableList<Vec3> = mutableListOf()
|
||||
|
||||
fun generateFlightPath(world: Level, radiusX: Double, radiusZ: Double, height: Double, steps: Int) {
|
||||
pathPoints.clear()
|
||||
|
||||
for (i in 0 until steps) {
|
||||
val angle = (i.toDouble() / steps) * Math.PI * 2
|
||||
val xOffset = radiusX * Math.cos(angle)
|
||||
val zOffset = radiusZ * Math.sin(angle)
|
||||
|
||||
val basePos = Vec3(blockPos.x + xOffset, blockPos.y + height, blockPos.z + zOffset)
|
||||
val adjustedPos = getValidPoint(world, basePos)
|
||||
|
||||
pathPoints.add(adjustedPos)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getValidPoint(world: Level, start: Vec3): Vec3 {
|
||||
val maxHeight = 40 // Max height for drone path
|
||||
val stepHeight = 1.0 // Step size for raycast
|
||||
|
||||
var adjustedHeight = start.y
|
||||
for (h in 0..maxHeight step stepHeight.toInt()) {
|
||||
val checkPos = BlockPos(start.x.toInt(), start.y.toInt() - h, start.z.toInt()) // Convert to BlockPos
|
||||
if (!world.getBlockState(checkPos).isAir) { // Check if block is solid
|
||||
return Vec3(start.x, start.y - h - 1, start.z) // Adjust position
|
||||
}
|
||||
}
|
||||
return start // No obstruction found
|
||||
}
|
||||
|
||||
|
||||
fun getPlayer1Pos(): BlockPos {
|
||||
return blockPos.north(10)
|
||||
}
|
||||
fun getPlayer2Pos(): BlockPos {
|
||||
return blockPos.south(10)
|
||||
}
|
||||
fun getPoke1Pos(): BlockPos {
|
||||
return blockPos.north(5)
|
||||
}
|
||||
fun getPoke2Pos(): BlockPos {
|
||||
return blockPos.south(5)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Saves data to NBT.
|
||||
*/
|
||||
override fun saveAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.saveAdditional(tag, registries)
|
||||
|
||||
// Save the isInUse state
|
||||
tag.putBoolean("IsInUse", isInUse)
|
||||
|
||||
// Save path points
|
||||
val pathTag = ListTag()
|
||||
for (point in pathPoints) {
|
||||
val pointTag = CompoundTag()
|
||||
pointTag.putDouble("x", point.x)
|
||||
pointTag.putDouble("y", point.y)
|
||||
pointTag.putDouble("z", point.z)
|
||||
pathTag.add(pointTag)
|
||||
}
|
||||
tag.put("PathPoints", pathTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads data from NBT.
|
||||
*/
|
||||
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
|
||||
super.loadAdditional(tag, registries)
|
||||
|
||||
// Load the isInUse state
|
||||
isInUse = tag.getBoolean("IsInUse")
|
||||
|
||||
// Load path points
|
||||
pathPoints.clear()
|
||||
val pathTag = tag.getList("PathPoints", 10) // 10 is the ID for CompoundTag
|
||||
for (i in 0 until pathTag.size) {
|
||||
val pointTag = pathTag.getCompound(i)
|
||||
val point = Vec3(pointTag.getDouble("x"), pointTag.getDouble("y"), pointTag.getDouble("z"))
|
||||
pathPoints.add(point)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getUpdatePacket(): Packet<ClientGamePacketListener>? {
|
||||
//println("getUpdatePacket called for NestBlockEntity at $blockPos with egg: $eggComponent")
|
||||
return ClientboundBlockEntityDataPacket.create(this)
|
||||
}
|
||||
|
||||
override fun getUpdateTag(registryLookup: HolderLookup.Provider): CompoundTag {
|
||||
val tag = saveWithoutMetadata(registryLookup)
|
||||
//println("getUpdateTag called for NestBlockEntity at $blockPos with tag: $tag")
|
||||
return tag
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
@@ -26,13 +26,7 @@ import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon
|
||||
import com.cobblemon.mod.common.client.render.DeferredRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.DisplayCaseRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.LecternBlockEntityRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
|
||||
import com.cobblemon.mod.common.client.render.block.*
|
||||
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
|
||||
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
|
||||
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
|
||||
@@ -60,6 +54,7 @@ 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.stadium.StadiumClientManager
|
||||
import com.cobblemon.mod.common.util.isLookingAt
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
@@ -116,6 +111,7 @@ object CobblemonClient {
|
||||
CobblemonDataProvider.canReload = true
|
||||
DeferredRenderer.clearAll()
|
||||
ClientPlayerIcon.clear()
|
||||
StadiumClientManager.onLogout()
|
||||
}
|
||||
|
||||
fun initialize(implementation: CobblemonClientImplementation) {
|
||||
@@ -260,7 +256,8 @@ object CobblemonClient {
|
||||
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
|
||||
CobblemonBlocks.GIMMIGHOUL_CHEST,
|
||||
CobblemonBlocks.DISPLAY_CASE,
|
||||
CobblemonBlocks.LECTERN
|
||||
CobblemonBlocks.LECTERN,
|
||||
CobblemonBlocks.STADIUM
|
||||
)
|
||||
|
||||
this.createBoatModelLayers()
|
||||
@@ -294,6 +291,7 @@ object CobblemonClient {
|
||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.GILDED_CHEST, ::GildedChestBlockRenderer)
|
||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.DISPLAY_CASE, ::DisplayCaseRenderer)
|
||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.LECTERN, ::LecternBlockEntityRenderer)
|
||||
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.STADIUM, ::StadiumBlockRenderer)
|
||||
}
|
||||
|
||||
private fun registerEntityRenderers() {
|
||||
|
||||
+2
-1
@@ -458,10 +458,11 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
formRightButton.render(context,mouseX, mouseY, delta)
|
||||
|
||||
val form = showableForms[selectedFormIndex]
|
||||
val formName = if (form.displayForm.lowercase() == "normal") "" else "-${form.displayForm.lowercase().replace("-", "")}"
|
||||
drawScaledTextJustifiedRight(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = lang("ui.pokedex.info.form.${form.displayForm.lowercase()}").bold(),
|
||||
text = lang("ui.pokedex.info.form.${species}${formName}").bold(),
|
||||
x = pX + 136,
|
||||
y = pY + 15,
|
||||
shadow = true
|
||||
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.block.entity.StadiumBlockEntity
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
class StadiumBlockRenderer(ctx: BlockEntityRendererProvider.Context) : BlockEntityRenderer<StadiumBlockEntity> {
|
||||
val context = RenderContext().also {
|
||||
it.put(RenderContext.DO_QUIRKS, false)
|
||||
it.put(RenderContext.RENDER_STATE, RenderContext.RenderState.BLOCK)
|
||||
}
|
||||
|
||||
private var pathIndex = 0
|
||||
private var animationTime = 0.0
|
||||
private val droneSpeed = 0.10
|
||||
|
||||
override fun render(
|
||||
blockEntity: StadiumBlockEntity,
|
||||
partialTick: Float,
|
||||
poseStack: PoseStack,
|
||||
bufferSource: MultiBufferSource,
|
||||
packedLight: Int,
|
||||
packedOverlay: Int
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
override fun render(
|
||||
blockEntity: StadiumBlockEntity,
|
||||
tickDelta: Float,
|
||||
poseStack: PoseStack,
|
||||
multiBufferSource: MultiBufferSource,
|
||||
light: Int,
|
||||
overlay: Int
|
||||
) {
|
||||
val blockState = blockEntity.blockState
|
||||
val yRot = blockState.getValue(HorizontalDirectionalBlock.FACING).toYRot()
|
||||
|
||||
val isClientSide = blockEntity.level?.isClientSide == true
|
||||
if (!isClientSide) return
|
||||
|
||||
val stadiumBlockState = blockEntity.level?.getBlockState(blockEntity.blockPos) ?: return
|
||||
if (stadiumBlockState.block != CobblemonBlocks.STADIUM) {
|
||||
return
|
||||
}
|
||||
|
||||
val droneState = blockEntity.droneState
|
||||
|
||||
|
||||
poseStack.pushPose()
|
||||
if (blockEntity.isInUse) {
|
||||
if (blockEntity.pathPoints.isEmpty()) {
|
||||
|
||||
poseStack.popPose()
|
||||
return
|
||||
}
|
||||
|
||||
spawnDebugParticles(blockEntity) // debug particles
|
||||
|
||||
// Center the drone at the block's center
|
||||
poseStack.translate(0.5, -3.0, 0.5)
|
||||
//poseStack.mulPose(Axis.XP.rotationDegrees(180F))
|
||||
//poseStack.mulPose(Axis.YP.rotationDegrees(180F))
|
||||
|
||||
val points = blockEntity.pathPoints
|
||||
val nextIndex = (pathIndex + 1) % points.size
|
||||
|
||||
val currentPoint = points[pathIndex]
|
||||
val nextPoint = points[nextIndex]
|
||||
|
||||
animationTime += tickDelta * droneSpeed
|
||||
if (animationTime >= 1.0) {
|
||||
animationTime = 0.0
|
||||
pathIndex = nextIndex
|
||||
}
|
||||
|
||||
val interpolatedPos = currentPoint.lerp(nextPoint, animationTime.toDouble())
|
||||
|
||||
println("DEBUG: Drone moving between points:")
|
||||
println(" - Current Point: ${currentPoint}")
|
||||
println(" - Next Point: ${nextPoint}")
|
||||
println(" - Interpolated Position: $interpolatedPos")
|
||||
|
||||
poseStack.translate(interpolatedPos.x - blockEntity.blockPos.x,
|
||||
interpolatedPos.y - blockEntity.blockPos.y,
|
||||
interpolatedPos.z - blockEntity.blockPos.z)
|
||||
|
||||
println("DEBUG: Drone position interpolated to: $interpolatedPos")
|
||||
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(-yRot))
|
||||
poseStack.mulPose(Axis.ZP.rotationDegrees(180F)) // flip the drone right side up
|
||||
|
||||
renderDrone(droneState, "sleep", tickDelta, poseStack, 1.0F, multiBufferSource, light)
|
||||
} else {
|
||||
val yRot = blockState.getValue(HorizontalDirectionalBlock.FACING).toYRot()
|
||||
|
||||
val poseEntry = poseStack.last()
|
||||
val matrix = poseEntry.pose()
|
||||
|
||||
poseStack.translate(0.5, 0.0, 0.5)
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(yRot))
|
||||
|
||||
val posX = matrix.m03()
|
||||
val posY = matrix.m13()
|
||||
val posZ = matrix.m23()
|
||||
|
||||
println("DEBUG: Drone is NOT in use. Rendering default position at: x=$posX, y=$posY, z=$posZ")
|
||||
|
||||
poseStack.mulPose(Axis.ZP.rotationDegrees(180F))
|
||||
renderDrone(droneState, "sleep", tickDelta, poseStack, 1.0F, multiBufferSource, light)
|
||||
}
|
||||
|
||||
poseStack.popPose()
|
||||
}
|
||||
|
||||
fun renderDrone(
|
||||
state: DroneState,
|
||||
pose: String,
|
||||
tickDelta: Float,
|
||||
poseStack: PoseStack,
|
||||
scale: Float = 1F,
|
||||
multiBufferSource: MultiBufferSource,
|
||||
light: Int,
|
||||
) {
|
||||
state.updatePartialTicks(tickDelta)
|
||||
|
||||
val droneResource: ResourceLocation = cobblemonResource("rotom_drone")
|
||||
|
||||
val model = VaryingModelRepository.getPoser(droneResource, state) as DroneModel
|
||||
val texture = VaryingModelRepository.getTexture(droneResource, state)
|
||||
|
||||
val buffer = multiBufferSource.getBuffer(RenderType.entityCutout(texture))
|
||||
model.bufferProvider = multiBufferSource
|
||||
|
||||
state.currentModel = model
|
||||
state.setPose(pose)
|
||||
|
||||
model.context = context
|
||||
context.put(RenderContext.TEXTURE, texture)
|
||||
context.put(RenderContext.RENDER_STATE, RenderContext.RenderState.BLOCK)
|
||||
context.put(RenderContext.POSABLE_STATE, state)
|
||||
|
||||
model.applyAnimations(
|
||||
entity = null,
|
||||
state = state,
|
||||
headYaw = 0F,
|
||||
headPitch = 0F,
|
||||
limbSwing = 0F,
|
||||
limbSwingAmount = 0F,
|
||||
ageInTicks = state.animationSeconds * 20
|
||||
)
|
||||
|
||||
poseStack.scale(scale, scale, scale)
|
||||
|
||||
// TODO: Make drone lighting dynamic (simply using the light arg makes the drone always appear dark)
|
||||
model.withLayerContext(multiBufferSource, state, VaryingModelRepository.getLayers(droneResource, state)) {
|
||||
model.render(context, poseStack, buffer, 200, OverlayTexture.NO_OVERLAY, -0x1)
|
||||
}
|
||||
model.setDefault()
|
||||
}
|
||||
|
||||
private fun spawnDebugParticles(blockEntity: StadiumBlockEntity) {
|
||||
val world = blockEntity.level ?: return
|
||||
if (!world.isClientSide) return // Only run on the client-side
|
||||
|
||||
for (point in blockEntity.pathPoints) {
|
||||
world.addParticle(
|
||||
net.minecraft.core.particles.ParticleTypes.FLAME, // Test particle (changeable)
|
||||
point.x, point.y, point.z, // Position of the particle
|
||||
0.0, 0.02, 0.0 // Slight upward motion
|
||||
)
|
||||
}
|
||||
|
||||
// Spawn a special particle at the next interpolation point
|
||||
if (blockEntity.pathPoints.isNotEmpty()) {
|
||||
val nextPoint = blockEntity.pathPoints[(pathIndex + 1) % blockEntity.pathPoints.size]
|
||||
world.addParticle(
|
||||
net.minecraft.core.particles.ParticleTypes.END_ROD, // Different effect for next point
|
||||
nextPoint.x, nextPoint.y, nextPoint.z,
|
||||
0.0, 0.05, 0.0
|
||||
)
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
+134
-3
@@ -35,6 +35,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.quirk.ModelQuirk
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.QuirkData
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.mojang.brigadier.StringReader
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException
|
||||
@@ -101,7 +102,8 @@ abstract class PosableState : Schedulable {
|
||||
val allActiveAnimations: List<ActiveAnimation> get() = activeAnimations + quirks.flatMap { it.value.animations }
|
||||
|
||||
/** The tick-driven age of the state. Combines with [currentPartialTicks] to produce the animation seconds. */
|
||||
protected var age = 0
|
||||
var age = 0
|
||||
protected set
|
||||
/**
|
||||
* The partial tick value of the state. Combines with [age] to produce the animation seconds. For entity-based state
|
||||
* this will be consistently reset to a new value, whereas non-entity-based state will increment this value.
|
||||
@@ -131,8 +133,137 @@ abstract class PosableState : Schedulable {
|
||||
/** A list of items to be rendered on a PosableModel during an animation */
|
||||
val animationItems = mutableMapOf<String, ItemStack>()
|
||||
|
||||
/** All of the MoLang functions that can be expose current riding data. */
|
||||
val ridingFunctions = QueryStruct(hashMapOf())
|
||||
.addFunction("pitch") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickPitch = pokemon.ridingAnimationData.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
|
||||
val maxPitch = 90.0
|
||||
return@addFunction DoubleValue((partialTickPitch / maxPitch).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("yaw") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickYaw = pokemon.ridingAnimationData.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
|
||||
val maxYaw = 180.0
|
||||
return@addFunction DoubleValue((partialTickYaw / maxYaw).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("roll") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickRoll = pokemon.ridingAnimationData.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
|
||||
val maxRoll = 180.0
|
||||
return@addFunction DoubleValue((partialTickRoll / maxRoll).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("pitch_change") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickPitchDelta = pokemon.ridingAnimationData.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
|
||||
//TODO: hook back up the retrieval of the current behaviors stat for this and the following functions
|
||||
val maxRotRate = 140.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickPitchDelta / maxRotRate).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("yaw_change") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickYawDelta = pokemon.ridingAnimationData.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
|
||||
//TODO: make this not hardcoded
|
||||
val maxRotRate = 140.0 //pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickYawDelta / maxRotRate).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("roll_change") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickRollDelta = pokemon.ridingAnimationData.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
|
||||
val maxRotRate = 140.0 //pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickRollDelta / maxRotRate).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("speed") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickSpeed = pokemon.ridingAnimationData.velocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).length()
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
return@addFunction DoubleValue((partialTickSpeed / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("velocity_x") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickXVel = pokemon.ridingAnimationData.velocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickXVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("velocity_y") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickYVel = pokemon.ridingAnimationData.velocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickYVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("velocity_z") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickZVel = pokemon.ridingAnimationData.velocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("velocity_right") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickZVel = pokemon.ridingAnimationData.localVelocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0) * -1.0)
|
||||
}
|
||||
.addFunction("velocity_upward") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickZVel = pokemon.ridingAnimationData.localVelocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("velocity_forward") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickZVel = pokemon.ridingAnimationData.localVelocitySpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
|
||||
|
||||
/** All of the MoLang functions that can be applied to something with this state. */
|
||||
val functions = QueryStruct(hashMapOf())
|
||||
val functions = QueryStruct(hashMapOf(
|
||||
"riding" to java.util.function.Function { ridingFunctions },
|
||||
"r" to java.util.function.Function { ridingFunctions }
|
||||
))
|
||||
.addFunction("anim_time") {
|
||||
reusableAnimTime.value = animationSeconds.toDouble()
|
||||
reusableAnimTime
|
||||
@@ -432,4 +563,4 @@ abstract class PosableState : Schedulable {
|
||||
1F
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -198,9 +198,11 @@ data class BedrockAnimation(
|
||||
|
||||
boneTimelines.forEach { (boneName, timeline) ->
|
||||
val part = relevantPartsByName[boneName] ?: if (boneName == "root_part") (rootPart as? ModelPart) else null
|
||||
val isCamera = boneName == "locator_camera"
|
||||
val scalar = if (isCamera) 1.0 else intensity.toDouble()
|
||||
if (part !== null) {
|
||||
if (!timeline.position.isEmpty()) {
|
||||
val position = timeline.position.resolve(animationSeconds.toDouble(), runtime).scale(intensity.toDouble())
|
||||
val position = timeline.position.resolve(animationSeconds.toDouble(), runtime).scale(scalar)
|
||||
part.apply {
|
||||
x += position.x.toFloat()
|
||||
y += position.y.toFloat()
|
||||
@@ -210,7 +212,7 @@ data class BedrockAnimation(
|
||||
|
||||
if (!timeline.rotation.isEmpty()) {
|
||||
try {
|
||||
val rotation = timeline.rotation.resolve(animationSeconds.toDouble(), runtime).scale(intensity.toDouble())
|
||||
val rotation = timeline.rotation.resolve(animationSeconds.toDouble(), runtime).scale(scalar)
|
||||
part.apply {
|
||||
xRot += rotation.x.toFloat().toRadians()
|
||||
yRot += rotation.y.toFloat().toRadians()
|
||||
@@ -230,14 +232,14 @@ data class BedrockAnimation(
|
||||
if (!timeline.scale.isEmpty()) {
|
||||
var scale = timeline.scale.resolve(animationSeconds.toDouble(), runtime)
|
||||
// If the goal is to make the invisible then kick that into gear after 0.5. Maybe could work better somehow else.
|
||||
if (scale == Vec3.ZERO && intensity > 0.5) {
|
||||
if (scale == Vec3.ZERO && scalar > 0.5) {
|
||||
part.xScale *= scale.x.toFloat()
|
||||
part.yScale *= scale.y.toFloat()
|
||||
part.zScale *= scale.z.toFloat()
|
||||
} else {
|
||||
// The deviation from 1 is what we want to multiply by the intensity of the animation.
|
||||
val deviation = scale.scale(-1.0).add(1.0, 1.0, 1.0)
|
||||
val weakenedDeviation = deviation.scale(intensity.toDouble())
|
||||
val weakenedDeviation = deviation.scale(scalar)
|
||||
scale = weakenedDeviation.subtract(1.0, 1.0, 1.0).scale(-1.0)
|
||||
part.xScale *= scale.x.toFloat()
|
||||
part.yScale *= scale.y.toFloat()
|
||||
@@ -394,4 +396,4 @@ enum class InterpolationType {
|
||||
|
||||
enum class Transformation {
|
||||
POSITION, ROTATION, SCALE
|
||||
}
|
||||
}
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.drone
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PoseAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.ModelQuirk
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
|
||||
/**
|
||||
* A model for rendering the Rotom drone used by the stadium block.
|
||||
*
|
||||
* @author Flarkinater
|
||||
* @since February 14th, 2025
|
||||
*/
|
||||
class DroneModel(root: Bone) : PosableModel(root) {
|
||||
@Transient
|
||||
@SerializedName("So this name can be literally anything, huh?")
|
||||
override val rootPart = (root as ModelPart).registerChildWithAllChildren(root.children.entries.first().key)
|
||||
var droneAnimations: Array<PoseAnimation> = emptyArray()
|
||||
var droneQuirks: Array<ModelQuirk<*>> = emptyArray()
|
||||
|
||||
override fun registerPoses() {
|
||||
registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = droneAnimations,
|
||||
quirks = droneQuirks
|
||||
)
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.drone
|
||||
|
||||
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
|
||||
/**
|
||||
* State for a drone Rotom attached to a stadium block.
|
||||
*
|
||||
* @author Flarkinater
|
||||
* @since February 12th, 2025
|
||||
*/
|
||||
class DroneState() : PosableState() {
|
||||
init {
|
||||
setPose("sleep")
|
||||
age = 0
|
||||
currentPartialTicks = 0F
|
||||
}
|
||||
|
||||
override fun getEntity() = null
|
||||
|
||||
override fun updatePartialTicks(partialTicks: Float) {
|
||||
currentPartialTicks += partialTicks / 2
|
||||
}
|
||||
|
||||
override val schedulingTracker = SchedulingTracker()
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
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.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class KangaskhanModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("kangaskhan")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 1.7F
|
||||
override var portraitTranslation = Vec3(-0.15, 1.1, 0.0)
|
||||
|
||||
override var profileScale = 0.7F
|
||||
override var profileTranslation = Vec3(0.0, 0.65, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("kangaskhan", "blink")}
|
||||
val blink2 = quirk { bedrockStateful("kangaskhan", "blink2")}
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink, blink2),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("kangaskhan", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink, blink2),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("kangaskhan", "ground_idle")
|
||||
//bedrock("kangaskhan", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("kangaskhan", "faint") else null
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen7
|
||||
|
||||
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.frame.QuadrupedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
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 MudsdaleModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("mudsdale")
|
||||
override val head = getPart("neck")
|
||||
|
||||
override val foreLeftLeg = getPart("leg_front_left")
|
||||
override val foreRightLeg = getPart("leg_front_right")
|
||||
override val hindLeftLeg = getPart("leg_back_left")
|
||||
override val hindRightLeg = getPart("leg_back_right")
|
||||
|
||||
override var portraitScale = 1.5F
|
||||
override var portraitTranslation = Vec3(-1.0, 1.76, 0.0)
|
||||
|
||||
override var profileScale = 0.5F
|
||||
override var profileTranslation = Vec3(0.0, 1.0, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var sleep: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("mudsdale", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("mudsdale", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("mudsdale", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(disableY = true),
|
||||
bedrock("mudsdale", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(disableY = true),
|
||||
bedrock("mudsdale", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("mudsdale", "faint") else null
|
||||
}
|
||||
+4
-2
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.*
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.blockentity.BlockEntityModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.fossil.FossilModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.drone.DroneModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.AncientPokeBallModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.BeastBallModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokeball.PokeBallModel
|
||||
@@ -79,12 +80,14 @@ object VaryingModelRepository {
|
||||
"poke_balls",
|
||||
"generic",
|
||||
"block_entities",
|
||||
"drone"
|
||||
)
|
||||
|
||||
val poserDirectories: List<Pair<String, Class<out PosableModel>>> = listOf(
|
||||
"bedrock/posers" to PosableModel::class.java,
|
||||
"bedrock/pokemon/posers" to PokemonPosableModel::class.java,
|
||||
"bedrock/fossils/posers" to FossilModel::class.java,
|
||||
"bedrock/drone/posers" to DroneModel::class.java,
|
||||
"bedrock/block_entities/posers" to BlockEntityModel::class.java,
|
||||
"bedrock/npcs/posers" to PosableModel::class.java,
|
||||
"bedrock/poke_balls/posers" to PosableModel::class.java,
|
||||
@@ -116,6 +119,7 @@ object VaryingModelRepository {
|
||||
.registerTypeAdapter(PosableModel::class.java, JsonModelAdapter(::PosableModel))
|
||||
.registerTypeAdapter(PokemonPosableModel::class.java, JsonModelAdapter(::PokemonPosableModel))
|
||||
.registerTypeAdapter(FossilModel::class.java, JsonModelAdapter(::FossilModel))
|
||||
.registerTypeAdapter(DroneModel::class.java, JsonModelAdapter(::DroneModel))
|
||||
.registerTypeAdapter(BlockEntityModel::class.java, JsonModelAdapter(::BlockEntityModel))
|
||||
.registerTypeAdapter(Pose::class.java, PoseAdapter { JsonModelAdapter.model!! })
|
||||
.registerTypeAdapter(ModelPartTransformation::class.java, ModelPartTransformationAdapter)
|
||||
@@ -287,7 +291,6 @@ object VaryingModelRepository {
|
||||
inbuilt("kabuto", ::KabutoModel)
|
||||
inbuilt("kabutops", ::KabutopsModel)
|
||||
inbuilt("kadabra", ::KadabraModel)
|
||||
inbuilt("kangaskhan", ::KangaskhanModel)
|
||||
inbuilt("koffing", ::KoffingModel)
|
||||
inbuilt("krabby", ::KrabbyModel)
|
||||
inbuilt("lickitung", ::LickitungModel)
|
||||
@@ -481,7 +484,6 @@ object VaryingModelRepository {
|
||||
inbuilt("taillow", ::TaillowModel)
|
||||
inbuilt("swellow", ::SwellowModel)
|
||||
inbuilt("mudbray", ::MudbrayModel)
|
||||
inbuilt("mudsdale", ::MudsdaleModel)
|
||||
inbuilt("comfey", ::ComfeyModel)
|
||||
inbuilt("tandemaus", ::TandemausModel)
|
||||
inbuilt("maushold", ::MausholdModel)
|
||||
|
||||
@@ -49,6 +49,8 @@ import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.SpeciesAdditions
|
||||
import com.cobblemon.mod.common.pokemon.properties.PropertiesCompletionProvider
|
||||
import com.cobblemon.mod.common.stadium.StadiumCameraManagers
|
||||
import com.cobblemon.mod.common.stadium.StadiumCameras
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
import com.cobblemon.mod.common.util.server
|
||||
@@ -97,6 +99,8 @@ object CobblemonDataProvider : DataProvider {
|
||||
this.register(CobblemonCosmeticItems)
|
||||
this.register(CobblemonFlows)
|
||||
this.register(CobblemonUnlockableWallpapers)
|
||||
this.register(StadiumCameras)
|
||||
this.register(StadiumCameraManagers)
|
||||
this.register(Marks)
|
||||
|
||||
CobblemonSpawnPools.load()
|
||||
|
||||
@@ -49,6 +49,8 @@ import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviours
|
||||
import com.cobblemon.mod.common.api.riding.events.SelectDriverEvent
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.riding.util.RidingAnimationData
|
||||
import com.cobblemon.mod.common.api.riding.util.Vec3Spring
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
import com.cobblemon.mod.common.api.scheduling.SchedulingTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
@@ -251,6 +253,7 @@ open class PokemonEntity(
|
||||
|
||||
var enablePoseTypeRecalculation = true
|
||||
|
||||
val ridingAnimationData: RidingAnimationData = RidingAnimationData()
|
||||
|
||||
var previousRidingState: RidingBehaviourState? = null
|
||||
var ridingState: RidingBehaviourState? = null
|
||||
@@ -483,6 +486,11 @@ open class PokemonEntity(
|
||||
entityData.get(MOVING)
|
||||
|
||||
super.tick()
|
||||
|
||||
if (passengers.isNotEmpty()) {
|
||||
ridingAnimationData.update(this)
|
||||
}
|
||||
|
||||
flyDistO = flyDist
|
||||
|
||||
if (isBattling) {
|
||||
@@ -1565,6 +1573,8 @@ open class PokemonEntity(
|
||||
inp.z * g.toDouble() + inp.x * f.toDouble()
|
||||
)
|
||||
|
||||
|
||||
|
||||
val diff = v.subtract(this.deltaMovement)
|
||||
|
||||
val inertia = ifRidingAvailableSupply(fallback = 0.5) { behaviour, settings, state ->
|
||||
@@ -1924,7 +1934,7 @@ open class PokemonEntity(
|
||||
// }
|
||||
|
||||
override fun onPassengerTurned(entityToUpdate: Entity) {
|
||||
if (entityToUpdate !is LivingEntity) return
|
||||
if (entityToUpdate !is LivingEntity) return
|
||||
ifRidingAvailable { behaviour, settings, state ->
|
||||
behaviour.clampPassengerRotation(settings, state, this, entityToUpdate)
|
||||
}
|
||||
@@ -1942,6 +1952,22 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
|
||||
// When riding mimic RemotePlayers logic for rendering players at farther
|
||||
// distances than usual. Otherwise the player may render when the pokemon
|
||||
// entity is not, causing a floating player.
|
||||
override fun shouldRenderAtSqrDistance(distance: Double): Boolean {
|
||||
if (!passengers.isEmpty()) {
|
||||
var d = (boundingBox.getSize() * 10.0)
|
||||
if (d.isNaN()) {
|
||||
d = 1.0
|
||||
}
|
||||
val scale = 64.0 * getViewScale()
|
||||
return distance < d * scale * scale
|
||||
}
|
||||
|
||||
return super.shouldRenderAtSqrDistance(distance)
|
||||
}
|
||||
|
||||
override fun getControllingPassenger(): LivingEntity? {
|
||||
val riders = this.passengers.filterIsInstance<LivingEntity>()
|
||||
if (riders.isEmpty()) {
|
||||
|
||||
@@ -238,6 +238,7 @@ object CobblemonItemGroups {
|
||||
entries.accept(CobblemonItems.PC)
|
||||
entries.accept(CobblemonItems.HEALING_MACHINE)
|
||||
entries.accept(CobblemonItems.PASTURE)
|
||||
entries.accept(CobblemonItems.STADIUM)
|
||||
|
||||
entries.accept(CobblemonItems.GILDED_CHEST)
|
||||
entries.accept(CobblemonItems.YELLOW_GILDED_CHEST)
|
||||
@@ -353,6 +354,18 @@ object CobblemonItemGroups {
|
||||
entries.accept(CobblemonItems.LEEK_AND_POTATO_STEW)
|
||||
entries.accept(CobblemonItems.BRAISED_VIVICHOKE)
|
||||
entries.accept(CobblemonItems.VIVICHOKE_DIP)
|
||||
entries.accept(CobblemonItems.TART_APPLE)
|
||||
entries.accept(CobblemonItems.SWEET_APPLE)
|
||||
entries.accept(CobblemonItems.SYRUPY_APPLE)
|
||||
entries.accept(CobblemonItems.WHIPPED_DREAM)
|
||||
entries.accept(CobblemonItems.STRAWBERRY_SWEET)
|
||||
entries.accept(CobblemonItems.LOVE_SWEET)
|
||||
entries.accept(CobblemonItems.BERRY_SWEET)
|
||||
entries.accept(CobblemonItems.CLOVER_SWEET)
|
||||
entries.accept(CobblemonItems.FLOWER_SWEET)
|
||||
entries.accept(CobblemonItems.STAR_SWEET)
|
||||
entries.accept(CobblemonItems.RIBBON_SWEET)
|
||||
|
||||
entries.accept(CobblemonItems.BERRY_JUICE)
|
||||
entries.accept(CobblemonItems.REMEDY)
|
||||
entries.accept(CobblemonItems.FINE_REMEDY)
|
||||
@@ -475,6 +488,7 @@ object CobblemonItemGroups {
|
||||
entries.accept(CobblemonItems.WHIPPED_DREAM)
|
||||
entries.accept(CobblemonItems.TART_APPLE)
|
||||
entries.accept(CobblemonItems.SWEET_APPLE)
|
||||
entries.accept(CobblemonItems.SYRUPY_APPLE)
|
||||
entries.accept(CobblemonItems.CRACKED_POT)
|
||||
entries.accept(CobblemonItems.CHIPPED_POT)
|
||||
entries.accept(CobblemonItems.MASTERPIECE_TEACUP)
|
||||
@@ -644,9 +658,23 @@ object CobblemonItemGroups {
|
||||
}
|
||||
|
||||
private fun foodInjections(injector: Injector) {
|
||||
injector.putAfter(CobblemonItems.TART_APPLE, Items.ENCHANTED_GOLDEN_APPLE)
|
||||
injector.putAfter(CobblemonItems.SWEET_APPLE, CobblemonItems.TART_APPLE)
|
||||
injector.putAfter(CobblemonItems.SYRUPY_APPLE, CobblemonItems.SWEET_APPLE)
|
||||
|
||||
injector.putAfter(CobblemonItems.MEDICINAL_LEEK, Items.POISONOUS_POTATO)
|
||||
injector.putAfter(CobblemonItems.ROASTED_LEEK, CobblemonItems.MEDICINAL_LEEK)
|
||||
injector.putAfter(CobblemonItems.BRAISED_VIVICHOKE, CobblemonItems.ROASTED_LEEK)
|
||||
|
||||
injector.putAfter(CobblemonItems.WHIPPED_DREAM, Items.PUMPKIN_PIE)
|
||||
injector.putAfter(CobblemonItems.STRAWBERRY_SWEET, CobblemonItems.WHIPPED_DREAM)
|
||||
injector.putAfter(CobblemonItems.LOVE_SWEET, CobblemonItems.STRAWBERRY_SWEET)
|
||||
injector.putAfter(CobblemonItems.BERRY_SWEET, CobblemonItems.LOVE_SWEET)
|
||||
injector.putAfter(CobblemonItems.CLOVER_SWEET, CobblemonItems.BERRY_SWEET)
|
||||
injector.putAfter(CobblemonItems.FLOWER_SWEET, CobblemonItems.CLOVER_SWEET)
|
||||
injector.putAfter(CobblemonItems.STAR_SWEET, CobblemonItems.FLOWER_SWEET)
|
||||
injector.putAfter(CobblemonItems.RIBBON_SWEET, CobblemonItems.STAR_SWEET)
|
||||
|
||||
injector.putAfter(CobblemonItems.LEEK_AND_POTATO_STEW, Items.RABBIT_STEW)
|
||||
injector.putAfter(CobblemonItems.VIVICHOKE_DIP, CobblemonItems.LEEK_AND_POTATO_STEW)
|
||||
}
|
||||
|
||||
@@ -10,10 +10,17 @@ package com.cobblemon.mod.common.item.interactive
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PrimaryAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockActiveAnimation
|
||||
import com.cobblemon.mod.common.item.CobblemonItem
|
||||
import com.cobblemon.mod.common.pokemon.Nature
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.stadium.StadiumClientManager
|
||||
import com.cobblemon.mod.common.stadium.deserialize
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@@ -45,9 +52,21 @@ class MintItem(val nature: Nature) : CobblemonItem(Properties()), PokemonSelecti
|
||||
}
|
||||
|
||||
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
if (user is ServerPlayer) {
|
||||
return use(user, user.getItemInHand(hand))
|
||||
// if (user is ServerPlayer) {
|
||||
// return use(user, user.getItemInHand(hand))
|
||||
// }
|
||||
if (!world.isClientSide) return InteractionResultHolder.fail(user.getItemInHand(hand))
|
||||
val pokemon = CobblemonClient.storage.myParty.first { it?.entity != null } ?: return InteractionResultHolder.fail(user.getItemInHand(hand))
|
||||
val entity = pokemon.entity ?: return InteractionResultHolder.fail(user.getItemInHand(hand))
|
||||
val delegate = entity.delegate as? PokemonClientDelegate ?: return InteractionResultHolder.fail(user.getItemInHand(hand))
|
||||
|
||||
val bedrockAnimation = when (pokemon.species.name) {
|
||||
"Tinkaton" -> (delegate.runtime.resolve("q.bedrock_primary('tinkaton', 'signature')".asExpression()).value() as ObjectValue<*>).obj as PrimaryAnimation
|
||||
"Tandemaus" -> (delegate.runtime.resolve("q.bedrock_primary('tandemaus', 'faint')".asExpression()).value() as ObjectValue<*>).obj as PrimaryAnimation
|
||||
else -> (delegate.runtime.resolve("q.bedrock_primary('ceruledge', 'battle_cry')".asExpression()).value() as ObjectValue<*>).obj as PrimaryAnimation
|
||||
}
|
||||
delegate.addPrimaryAnimation(bedrockAnimation)
|
||||
StadiumClientManager.playAnimation(entity, bedrockAnimation)
|
||||
return InteractionResultHolder.success(user.getItemInHand(hand))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.platform.events
|
||||
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
class ChangeDimensionEvent(val player: ServerPlayer)
|
||||
class ChangeDimensionEvent(val player: ServerPlayer, val origin: ServerLevel?, val destination: ServerLevel?)
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
|
||||
import com.google.gson.GsonBuilder
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Vector3f
|
||||
|
||||
val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter(Vec3::class.java, Vec3dAdapter)
|
||||
.create()
|
||||
|
||||
fun deserialize(data: String): CameraAnimation {
|
||||
return gson.fromJson(data, CameraAnimation::class.java)
|
||||
}
|
||||
|
||||
data class CameraAnimation(
|
||||
val length: Double,
|
||||
val origin: CameraOrigin,
|
||||
val timeline: Timeline
|
||||
)
|
||||
|
||||
data class Timeline(
|
||||
val position: Map<Double, Vec3>,
|
||||
val rotation: Map<Double, Vec3>,
|
||||
)
|
||||
|
||||
data class CameraOrigin(
|
||||
val position: Vec3,
|
||||
val rotation: Vec3,
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import java.util.*
|
||||
|
||||
abstract class StadiumBattleDefenition {
|
||||
var stadiumBattleID: UUID = UUID.randomUUID()
|
||||
|
||||
var participants: MutableList<UUID> = mutableListOf<UUID>()
|
||||
var spectators: MutableList<UUID> = mutableListOf<UUID>()
|
||||
|
||||
var cameras: MutableList<StadiumCameraEntry> = mutableListOf<StadiumCameraEntry>()
|
||||
|
||||
abstract fun readyForBattle(): Boolean
|
||||
|
||||
abstract fun canAddPlayer(player: ServerPlayer): Boolean
|
||||
|
||||
abstract fun addPlayer(player: ServerPlayer)
|
||||
|
||||
abstract fun getPlayers(): MutableList<ServerPlayer>
|
||||
|
||||
abstract fun initializeBattle()
|
||||
|
||||
abstract fun getCurrentCamera(): StadiumCameraEntry
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import net.fabricmc.loader.impl.lib.sat4j.core.Vec
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Vector3f
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.atan
|
||||
import kotlin.math.atan2
|
||||
|
||||
class StadiumCameraEntry(
|
||||
var id: ResourceLocation,
|
||||
val length: Double = 0.0,
|
||||
val positionTimeline: MutableMap<String, CameraKeyFrame> = mutableMapOf(),
|
||||
val targetPositionTimeline: MutableMap<String, CameraKeyFrame> = mutableMapOf(),
|
||||
val move: String = ""
|
||||
) {
|
||||
fun resolvePosition(time: Double): Vec3 {
|
||||
return resolvePosition(time, positionTimeline)
|
||||
}
|
||||
|
||||
private fun resolvePosition(time: Double, map: MutableMap<String, CameraKeyFrame>): Vec3 {
|
||||
val runtime = StadiumClientManager.runtime
|
||||
runtime.environment.setSimpleVariable("anim_time", DoubleValue(time))
|
||||
var frame1: CameraKeyFrame? = null
|
||||
var frame2: CameraKeyFrame? = null
|
||||
var time1 = -1.0
|
||||
var time2 = -1.0
|
||||
for (keyframe in map) {
|
||||
if (time >= keyframe.key.toDouble()) {
|
||||
if (time1 == -1.0 || abs(time - keyframe.key.toDouble()) < abs(time - time1)) {
|
||||
frame1 = keyframe.value
|
||||
time1 = keyframe.key.toDouble()
|
||||
}
|
||||
}
|
||||
if (time < keyframe.key.toDouble()) {
|
||||
if (time2 == -1.0 || abs(time - keyframe.key.toDouble()) < abs(time - time2)) {
|
||||
frame2 = keyframe.value
|
||||
time2 = keyframe.key.toDouble()
|
||||
}
|
||||
}
|
||||
}
|
||||
val difference = (time - time1) / (time2 - time1)
|
||||
|
||||
if (frame1 != null && frame1.interpolation == CameraInterpolation.STEP) {
|
||||
frame2 = null
|
||||
}
|
||||
|
||||
if (frame1 == null && frame2 == null) {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
else if (frame1 == null) {
|
||||
frame2!!
|
||||
val x = runtime.resolveDouble(frame2.x)
|
||||
val y = runtime.resolveDouble(frame2.y)
|
||||
val z = runtime.resolveDouble(frame2.z)
|
||||
return Vec3(x,y,z)
|
||||
}
|
||||
else if (frame2 == null) {
|
||||
val x = runtime.resolveDouble(frame1.x)
|
||||
val y = runtime.resolveDouble(frame1.y)
|
||||
val z = runtime.resolveDouble(frame1.z)
|
||||
return Vec3(x,y,z)
|
||||
}
|
||||
else {
|
||||
val x1 = runtime.resolveDouble(frame1.x)
|
||||
val y1 = runtime.resolveDouble(frame1.y)
|
||||
val z1 = runtime.resolveDouble(frame1.z)
|
||||
val vec1 = Vec3(x1,y1,z1)
|
||||
val x2 = runtime.resolveDouble(frame2.x)
|
||||
val y2 = runtime.resolveDouble(frame2.y)
|
||||
val z2 = runtime.resolveDouble(frame2.z)
|
||||
val vec2 = Vec3(x2,y2,z2)
|
||||
return vec1.lerp(vec2, difference)
|
||||
}
|
||||
}
|
||||
|
||||
fun resolveRotation(time: Double): Vector3f {
|
||||
val position = resolvePosition(time, positionTimeline)
|
||||
val target = resolvePosition(time, targetPositionTimeline)
|
||||
val offset = target.subtract(position)
|
||||
val xRot = -atan(offset.y.toFloat()/offset.horizontalDistance().toFloat()) * (180F / Math.PI.toFloat())
|
||||
val yRot = -atan2(offset.x.toFloat(),offset.z.toFloat()) * (180F / Math.PI.toFloat())
|
||||
return Vector3f(xRot, yRot, 0.0F)
|
||||
}
|
||||
|
||||
fun encode(buf: RegistryFriendlyByteBuf) {
|
||||
buf.writeIdentifier(id)
|
||||
buf.writeDouble(length)
|
||||
buf.writeMap(positionTimeline, {_, key -> buf.writeString(key)}, {_, value ->
|
||||
buf.writeString(value.x.getString())
|
||||
buf.writeString(value.y.getString())
|
||||
buf.writeString(value.z.getString())
|
||||
buf.writeEnum(value.interpolation)
|
||||
})
|
||||
buf.writeMap(targetPositionTimeline, {_, key -> buf.writeString(key)}, {_, value ->
|
||||
buf.writeString(value.x.getString())
|
||||
buf.writeString(value.y.getString())
|
||||
buf.writeString(value.z.getString())
|
||||
buf.writeEnum(value.interpolation)
|
||||
})
|
||||
buf.writeString(move)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buf: RegistryFriendlyByteBuf) : StadiumCameraEntry {
|
||||
val id = buf.readIdentifier()
|
||||
val length = buf.readDouble()
|
||||
val positionTimeline = buf.readMap({_ -> buf.readString()}, {_ ->
|
||||
CameraKeyFrame(buf.readString().asExpression(), buf.readString().asExpression(), buf.readString().asExpression(), buf.readEnum(CameraInterpolation::class.java))
|
||||
}).toMutableMap()
|
||||
val targetPositionTimeline = buf.readMap({_ -> buf.readString()}, {_ ->
|
||||
CameraKeyFrame(buf.readString().asExpression(), buf.readString().asExpression(), buf.readString().asExpression(), buf.readEnum(CameraInterpolation::class.java))
|
||||
}).toMutableMap()
|
||||
val move = buf.readString()
|
||||
|
||||
return StadiumCameraEntry(id, length, positionTimeline, targetPositionTimeline, move)
|
||||
}
|
||||
}
|
||||
|
||||
data class CameraKeyFrame (
|
||||
val x: Expression,
|
||||
val y: Expression,
|
||||
val z: Expression,
|
||||
val interpolation: CameraInterpolation
|
||||
)
|
||||
|
||||
enum class CameraInterpolation {
|
||||
LINEAR,
|
||||
STEP
|
||||
}
|
||||
|
||||
object CameraEntryAdapter: JsonDeserializer<StadiumCameraEntry> {
|
||||
override fun deserialize(
|
||||
json: JsonElement?,
|
||||
typeOfT: Type?,
|
||||
context: JsonDeserializationContext?
|
||||
): StadiumCameraEntry {
|
||||
if (json is JsonObject) {
|
||||
val length = json["length"]?.asDouble ?: 0.0
|
||||
val positionTimeline = mutableMapOf<String, CameraKeyFrame>()
|
||||
json["positions"]?.asJsonObject?.entrySet()?.forEach { (name, position) ->
|
||||
val xyz = position.asJsonObject["xyz"]
|
||||
var x = "0.0".asExpression()
|
||||
var y = "0.0".asExpression()
|
||||
var z = "0.0".asExpression()
|
||||
if (xyz != null && xyz.isJsonArray && xyz.asJsonArray.size() == 3) {
|
||||
x = xyz.asJsonArray[0].asString.asExpression()
|
||||
y = xyz.asJsonArray[1].asString.asExpression()
|
||||
z = xyz.asJsonArray[2].asString.asExpression()
|
||||
}
|
||||
val interpolation = when (position.asJsonObject["interpolation"]?.asString) {
|
||||
"linear" -> CameraInterpolation.LINEAR
|
||||
"step" -> CameraInterpolation.STEP
|
||||
else -> CameraInterpolation.LINEAR
|
||||
}
|
||||
positionTimeline[name] = CameraKeyFrame(x, y, z, interpolation)
|
||||
}
|
||||
val targetPositionTimeline = mutableMapOf<String, CameraKeyFrame>()
|
||||
json["targetPositions"]?.asJsonObject?.entrySet()?.forEach { (name, position) ->
|
||||
val xyz = position.asJsonObject["xyz"]
|
||||
var x = "0.0".asExpression()
|
||||
var y = "0.0".asExpression()
|
||||
var z = "0.0".asExpression()
|
||||
if (xyz != null && xyz.isJsonArray && xyz.asJsonArray.size() == 3) {
|
||||
x = xyz.asJsonArray[0].asString.asExpression()
|
||||
y = xyz.asJsonArray[1].asString.asExpression()
|
||||
z = xyz.asJsonArray[2].asString.asExpression()
|
||||
}
|
||||
val interpolation = when (position.asJsonObject["interpolation"]?.asString) {
|
||||
"linear" -> CameraInterpolation.LINEAR
|
||||
"step" -> CameraInterpolation.STEP
|
||||
else -> CameraInterpolation.LINEAR
|
||||
}
|
||||
targetPositionTimeline[name] = CameraKeyFrame(x, y, z, interpolation)
|
||||
}
|
||||
val move = json["move"]?.asString ?: ""
|
||||
}
|
||||
throw IllegalStateException("Stadium Camera could not be parsed")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import java.lang.reflect.Type
|
||||
|
||||
class StadiumCameraManagerEntry(
|
||||
var id: ResourceLocation,
|
||||
val states: MutableMap<String, StadiumCameraState>,
|
||||
val startingState: String
|
||||
) {
|
||||
fun encode(buf: RegistryFriendlyByteBuf) {
|
||||
buf.writeIdentifier(id)
|
||||
buf.writeMap(states, {_, key -> buf.writeString(key)}, {_, value -> value.encode(buf)})
|
||||
buf.writeString(startingState)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buf: RegistryFriendlyByteBuf): StadiumCameraManagerEntry {
|
||||
val id = buf.readIdentifier()
|
||||
val states = buf.readMap({buf.readString()}, {StadiumCameraState.decode(buf)}).toMutableMap()
|
||||
val startState = buf.readString()
|
||||
return StadiumCameraManagerEntry(id, states, startState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StadiumCameraState(
|
||||
val camera: Expression,
|
||||
val target: StadiumCameraTarget,
|
||||
val listOfTransitions: MutableList<StadiumCameraTransition>,
|
||||
val loop: Boolean
|
||||
) {
|
||||
fun encode(buf: RegistryFriendlyByteBuf) {
|
||||
buf.writeString(camera.originalString)
|
||||
buf.writeEnum(target)
|
||||
buf.writeCollection(listOfTransitions) {_, transition -> transition.encode(buf)}
|
||||
buf.writeBoolean(loop)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buf: RegistryFriendlyByteBuf): StadiumCameraState {
|
||||
val camera = buf.readString().asExpression()
|
||||
val target = buf.readEnum(StadiumCameraTarget::class.java)
|
||||
val listOfTransitions = buf.readList { StadiumCameraTransition.decode(buf) }.toMutableList()
|
||||
val loop = buf.readBoolean()
|
||||
return StadiumCameraState(camera, target, listOfTransitions, loop)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StadiumCameraTransition(
|
||||
val targetState: String,
|
||||
val checkOnEnd: Boolean,
|
||||
val condition: Expression
|
||||
) {
|
||||
fun encode(buf: RegistryFriendlyByteBuf) {
|
||||
buf.writeString(targetState)
|
||||
buf.writeBoolean(checkOnEnd)
|
||||
buf.writeString(condition.originalString)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buf: RegistryFriendlyByteBuf): StadiumCameraTransition {
|
||||
val targetState = buf.readString()
|
||||
val checkOnEnd = buf.readBoolean()
|
||||
val condition = buf.readString().asExpression()
|
||||
return StadiumCameraTransition(targetState, checkOnEnd, condition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class StadiumCameraTarget {
|
||||
CENTRE,
|
||||
ACTIVE_POKEMON,
|
||||
ENEMY_POKEMON,
|
||||
TRAINER
|
||||
}
|
||||
|
||||
object StadiumCameraManagerAdapter: JsonDeserializer<StadiumCameraManagerEntry> {
|
||||
override fun deserialize(
|
||||
json: JsonElement?,
|
||||
typeOfT: Type?,
|
||||
context: JsonDeserializationContext?
|
||||
): StadiumCameraManagerEntry {
|
||||
if (json is JsonObject) {
|
||||
val states = mutableMapOf<String, StadiumCameraState>()
|
||||
json["states"]?.asJsonObject?.entrySet()?.forEach { (name, state) ->
|
||||
val camera = state.asJsonObject["camera"]?.asString?.asExpression() ?: "".asExpression()
|
||||
val target = when (state.asJsonObject["target"]?.asString) {
|
||||
"CENTRE" -> StadiumCameraTarget.CENTRE
|
||||
"ACTIVE_POKEMON" -> StadiumCameraTarget.ACTIVE_POKEMON
|
||||
"ENEMY_POKEMON" -> StadiumCameraTarget.ENEMY_POKEMON
|
||||
"TRAINER" -> StadiumCameraTarget.TRAINER
|
||||
else -> StadiumCameraTarget.CENTRE
|
||||
}
|
||||
val listOfTransitions = mutableListOf<StadiumCameraTransition>()
|
||||
state.asJsonObject["transitions"]?.asJsonArray?.forEach {
|
||||
val targetState = it.asJsonObject["targetState"]?.asString ?: ""
|
||||
val checkOnEnd = it.asJsonObject["checkOnEnd"]?.asBoolean ?: false
|
||||
val condition = it.asJsonObject["condition"]?.asString?.asExpression() ?: "0.0".asExpression()
|
||||
listOfTransitions.add(StadiumCameraTransition(targetState, checkOnEnd, condition))
|
||||
}
|
||||
val loop = state.asJsonObject["loop"]?.asBoolean ?: false
|
||||
states[name] = StadiumCameraState(camera, target, listOfTransitions, loop)
|
||||
}
|
||||
val startingState = json["startingState"].asString ?: ""
|
||||
return StadiumCameraManagerEntry(cobblemonResource(""), states, startingState)
|
||||
}
|
||||
throw IllegalStateException("StadiumCameraManager could not be parsed")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object StadiumCameraManagers: JsonDataRegistry<StadiumCameraManagerEntry> {
|
||||
override val id = cobblemonResource("stadium_managers")
|
||||
override val type = PackType.SERVER_DATA
|
||||
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(StadiumCameraManagerEntry::class.java, StadiumCameraManagerAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken: TypeToken<StadiumCameraManagerEntry> = TypeToken.get(StadiumCameraManagerEntry::class.java)
|
||||
override val resourcePath = "stadium_managers"
|
||||
|
||||
val managers = mutableMapOf<ResourceLocation, StadiumCameraManagerEntry>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, StadiumCameraManagerEntry>) {
|
||||
managers.clear()
|
||||
data.forEach { location, manager ->
|
||||
manager.id = location
|
||||
managers[location] = manager
|
||||
}
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
override val observable = SimpleObservable<StadiumCameraManagers>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
StadiumCameraManagersSyncPacket(managers.values).sendToPlayer(player)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.cobblemon.mod.common.net.messages.client.data.DataRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class StadiumCameraManagersSyncPacket(managers: Collection<StadiumCameraManagerEntry>) :
|
||||
DataRegistrySyncPacket<StadiumCameraManagerEntry, StadiumCameraManagersSyncPacket>(managers) {
|
||||
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: StadiumCameraManagerEntry) {
|
||||
entry.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): StadiumCameraManagerEntry? {
|
||||
return StadiumCameraManagerEntry.decode(buffer)
|
||||
}
|
||||
|
||||
override fun synchronizeDecoded(entries: Collection<StadiumCameraManagerEntry>) {
|
||||
StadiumCameraManagers.reload(entries.associateBy { it.id })
|
||||
}
|
||||
|
||||
override val id = ID
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("stadium_camera_managers_sync")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = StadiumCameraManagersSyncPacket(emptyList()).apply { decodeBuffer(buffer) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object StadiumCameras: JsonDataRegistry<StadiumCameraEntry> {
|
||||
override val id = cobblemonResource("stadium_cameras")
|
||||
override val type = PackType.SERVER_DATA
|
||||
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(StadiumCameraEntry::class.java, StadiumCameraEntry.CameraEntryAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken: TypeToken<StadiumCameraEntry> = TypeToken.get(StadiumCameraEntry::class.java)
|
||||
override val resourcePath = "stadium_cameras"
|
||||
|
||||
val cameras = mutableMapOf<ResourceLocation, StadiumCameraEntry>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, StadiumCameraEntry>) {
|
||||
cameras.clear()
|
||||
data.forEach { location, camera ->
|
||||
camera.id = location
|
||||
cameras[location] = camera
|
||||
}
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
override val observable = SimpleObservable<StadiumCameras>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
StadiumCamerasSyncPacket(cameras.values).sendToPlayer(player)
|
||||
}
|
||||
|
||||
fun getMoveCamera(move: String): StadiumCameraEntry? {
|
||||
return cameras.values.firstOrNull { it.move == move }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.cobblemon.mod.common.net.messages.client.data.DataRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class StadiumCamerasSyncPacket(cameras: Collection<StadiumCameraEntry>) :
|
||||
DataRegistrySyncPacket<StadiumCameraEntry, StadiumCamerasSyncPacket>(cameras) {
|
||||
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: StadiumCameraEntry) {
|
||||
entry.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): StadiumCameraEntry? {
|
||||
return StadiumCameraEntry.decode(buffer)
|
||||
}
|
||||
|
||||
override fun synchronizeDecoded(entries: Collection<StadiumCameraEntry>) {
|
||||
StadiumCameras.reload(entries.associateBy { it.id })
|
||||
}
|
||||
|
||||
override val id = ID
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("stadium_cameras_sync")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = StadiumCamerasSyncPacket(emptyList()).apply { decodeBuffer(buffer) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PrimaryAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.linearLerpAlpha
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asResource
|
||||
import com.cobblemon.mod.common.util.math.fromEulerXYZ
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.util.math.toEulerXYZ
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix4f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
import com.cobblemon.mod.common.util.plus
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
object StadiumClientManager {
|
||||
//Molang
|
||||
fun MoLangRuntime.setupCameraFunctions(): MoLangRuntime {
|
||||
environment.query.addFunctions(
|
||||
hashMapOf(
|
||||
"moveCamera" to Function { params ->
|
||||
if (params.get<MoValue>(0) !is StringValue) {
|
||||
return@Function Unit
|
||||
}
|
||||
val camera = StadiumCameras.getMoveCamera(params.get<MoValue>(0).asString())
|
||||
return@Function camera?.id?.toString() ?: ""
|
||||
}
|
||||
)
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
val runtime = MoLangRuntime().setup().setupClient().setupCameraFunctions()
|
||||
|
||||
var currentStadiumBattleUUID: UUID? = null
|
||||
|
||||
var Instruction = "DEFAULT"
|
||||
var InstructionChangeTime = 0.0
|
||||
var InstructionJustChanged = false
|
||||
|
||||
fun updateState(newState: String) {
|
||||
Instruction = newState
|
||||
InstructionChangeTime = 0.0
|
||||
InstructionJustChanged = true
|
||||
}
|
||||
|
||||
fun onLogout() {
|
||||
currentStadiumBattleUUID = null
|
||||
}
|
||||
|
||||
fun handleJoin(battleUUID: UUID, cameraManager: ResourceLocation) {
|
||||
currentStadiumBattleUUID = battleUUID
|
||||
activeCameraManager = cameraManager
|
||||
|
||||
cameraTimer = 0.0
|
||||
currentCameraState = StadiumCameraManagers.managers[cameraManager]!!.startingState
|
||||
cameraPosition = Vec3.ZERO
|
||||
cameraRotation = Quaternionf()
|
||||
updateCameraData(0.0)
|
||||
}
|
||||
|
||||
fun inStadiumBattle(): Boolean {
|
||||
return currentStadiumBattleUUID != null
|
||||
}
|
||||
|
||||
fun shouldUseStadiumCamera(): Boolean {
|
||||
return animation != null
|
||||
}
|
||||
|
||||
//Molang Data
|
||||
fun updateMolangVar() {
|
||||
val environment = runtime.environment
|
||||
environment.setSimpleVariable("instruction", StringValue(Instruction))
|
||||
//environment.setSimpleVariable("instructionChangeTime", DoubleValue(InstructionChangeTime))
|
||||
environment.setSimpleVariable("instructionJustChanged", DoubleValue(InstructionJustChanged))
|
||||
val isSpectating = CobblemonClient.battle?.spectating ?: false
|
||||
environment.setSimpleVariable("isBattling", DoubleValue(!isSpectating))
|
||||
environment.setSimpleVariable("isSpectating", DoubleValue(isSpectating))
|
||||
}
|
||||
|
||||
fun instructionUpdate(newState: String, additionalValues: MutableMap<String, MoValue>) {
|
||||
val environment = runtime.environment
|
||||
Instruction = newState
|
||||
InstructionChangeTime = 0.0
|
||||
InstructionJustChanged = true
|
||||
for (value in additionalValues) {
|
||||
environment.setSimpleVariable(value.key, value.value)
|
||||
}
|
||||
}
|
||||
|
||||
//Camera Manager
|
||||
var activeCameraManager: ResourceLocation? = null
|
||||
var cameraTimer: Double = 0.0
|
||||
var currentCameraState: String = ""
|
||||
var nextCameraState: String = ""
|
||||
var calculateNextState: Boolean = true
|
||||
|
||||
fun tickCameraManager() {
|
||||
if (!shouldUseStadiumCamera()) return
|
||||
|
||||
//Molang Variables
|
||||
val environment = runtime.environment
|
||||
if (CobblemonClient.battle != null) {
|
||||
environment.setSimpleVariable("selectingMove", DoubleValue(CobblemonClient.battle!!.mustChoose))
|
||||
}
|
||||
else {
|
||||
environment.setSimpleVariable("selectingMove", DoubleValue(0.0))
|
||||
}
|
||||
|
||||
val currentManager = StadiumCameraManagers.managers[activeCameraManager]!!
|
||||
val currentState = currentManager.states[currentCameraState]!!
|
||||
val currentCamera = StadiumCameras.cameras[runtime.resolveString(currentState.camera).asResource()]
|
||||
|
||||
InstructionChangeTime += 0.05
|
||||
if (currentCamera != null) {
|
||||
cameraTimer += 0.05
|
||||
if (cameraTimer > currentCamera.length) {
|
||||
if (currentState.loop) {
|
||||
cameraTimer -= currentCamera.length
|
||||
}
|
||||
else {
|
||||
cameraTimer = currentCamera.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!calculateNextState) {
|
||||
currentCameraState = nextCameraState
|
||||
calculateNextState = true
|
||||
|
||||
cameraTimer = if (currentCamera != null && currentCamera.length != 0.0) cameraTimer - currentCamera.length else 0.0
|
||||
}
|
||||
else {
|
||||
updateMolangVar()
|
||||
environment.setSimpleVariable("instructionChangeTime", DoubleValue(InstructionChangeTime))
|
||||
|
||||
val endOfAnim = if (currentCamera != null) cameraTimer + 1/20 >= currentCamera.length else true
|
||||
|
||||
val nextState = evaluateTransitions(currentState, endOfAnim)
|
||||
if (nextState != null) {
|
||||
nextCameraState = nextState.targetState
|
||||
while (true) {
|
||||
val newState = currentManager.states[nextCameraState]!!
|
||||
val newCamera = StadiumCameras.cameras[runtime.resolveString(newState.camera).asResource()]
|
||||
val newEndOfAnim = if (newCamera != null) newCamera.length == 0.0 else true
|
||||
|
||||
val newNextState = evaluateTransitions(newState, newEndOfAnim)
|
||||
if (newNextState == null) {
|
||||
break
|
||||
}
|
||||
else {
|
||||
nextCameraState = newNextState.targetState
|
||||
}
|
||||
}
|
||||
calculateNextState = false
|
||||
}
|
||||
}
|
||||
if (InstructionJustChanged) {
|
||||
InstructionJustChanged = false
|
||||
Instruction = "NONE"
|
||||
}
|
||||
}
|
||||
|
||||
private fun evaluateTransitions(state: StadiumCameraState, checkEnd: Boolean) : StadiumCameraTransition? {
|
||||
var nextState = state.listOfTransitions.firstOrNull { !it.checkOnEnd && runtime.resolveBoolean(it.condition) }
|
||||
if (nextState == null && checkEnd) {
|
||||
nextState = state.listOfTransitions.firstOrNull { it.checkOnEnd && runtime.resolveBoolean(it.condition) }
|
||||
}
|
||||
return nextState
|
||||
}
|
||||
|
||||
var cameraPosition: Vec3 = Vec3.ZERO
|
||||
var cameraRotation: Quaternionf = Quaternionf()
|
||||
|
||||
var startTime = 0.0
|
||||
var startPosition: Vec3? = null
|
||||
var startRotation: Vector3f? = null
|
||||
var attackAnimationPokemon: PokemonEntity? = null
|
||||
var animation: PrimaryAnimation? = null
|
||||
var oldFov: Int = 0
|
||||
|
||||
fun playAnimation(pokemon: PokemonEntity, animation: PrimaryAnimation) {
|
||||
if (startTime != 0.0) return
|
||||
attackAnimationPokemon = pokemon
|
||||
this.animation = animation
|
||||
this.oldFov = Minecraft.getInstance().options.fov().get()
|
||||
animation.afterAction += {
|
||||
cameraPosition = Vec3.ZERO
|
||||
cameraRotation = Quaternionf()
|
||||
attackAnimationPokemon = null
|
||||
this.animation = null
|
||||
Minecraft.getInstance().options.fov().set(oldFov)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateCameraData(delta: Double) {
|
||||
val pokemon = attackAnimationPokemon ?: return
|
||||
val delegate = pokemon.delegate as? PokemonClientDelegate ?: return
|
||||
|
||||
delegate.updatePartialTicks(delta.toFloat())
|
||||
MountedPokemonAnimationRenderController.reset()
|
||||
MountedPokemonAnimationRenderController.setup(pokemon, delta.toFloat())
|
||||
|
||||
val locator = delegate.locatorStates["camera"] ?: return
|
||||
|
||||
cameraPosition = locator.position.add(locator.matrix.getTranslation(Vector3f()).toVec3d())
|
||||
cameraRotation = locator.matrix.getUnnormalizedRotation(Quaternionf()).normalize()
|
||||
val cameraPart = delegate.currentModel?.getPart("locator_camera") ?: return
|
||||
val fov = cameraPart.zScale.toInt()
|
||||
if (Minecraft.getInstance().options.fov().get() != fov) {
|
||||
Minecraft.getInstance().options.fov().set(fov)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
class StadiumFormat {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object StadiumJoinHandler: ClientNetworkPacketHandler<StadiumJoinPacket> {
|
||||
override fun handle(packet: StadiumJoinPacket, client: Minecraft) {
|
||||
StadiumClientManager.handleJoin(packet.joiningBattle, packet.cameraManager)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import java.util.*
|
||||
|
||||
class StadiumJoinPacket(
|
||||
val joiningBattle: UUID,
|
||||
val cameraManager: ResourceLocation
|
||||
): NetworkPacket<StadiumJoinPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(this.joiningBattle)
|
||||
buffer.writeIdentifier(cameraManager)
|
||||
}
|
||||
companion object {
|
||||
val ID = cobblemonResource("stadium_join")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = StadiumJoinPacket(buffer.readUUID(), buffer.readIdentifier())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import java.util.UUID
|
||||
|
||||
object StadiumServerManager {
|
||||
val activeStadiumBattles = mutableMapOf<UUID, StadiumBattleInstance>()
|
||||
|
||||
fun createNewStadiumBattle(battle: UUID, managerResource: ResourceLocation, participants: MutableList<UUID> = mutableListOf<UUID>()) {
|
||||
val newInstance = StadiumBattleInstance(battle, managerResource)
|
||||
newInstance.participants = participants
|
||||
activeStadiumBattles[battle] = newInstance
|
||||
}
|
||||
|
||||
fun terminateNewStadiumBattle(battle: UUID) {
|
||||
activeStadiumBattles.remove(battle)
|
||||
}
|
||||
|
||||
fun addPlayerToStadiumBattle(battle: UUID, player: UUID) {
|
||||
val instance = activeStadiumBattles[battle]
|
||||
if (instance != null) {
|
||||
if (!instance.participants.contains(player)) instance.participants.add(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StadiumBattleInstance(
|
||||
val stadiumBattleId: UUID,
|
||||
val managerResource: ResourceLocation
|
||||
){
|
||||
var participants = mutableListOf<UUID>()
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.cobblemon.mod.common.stadium
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.BattleBuilder
|
||||
import com.cobblemon.mod.common.battles.SuccessfulBattleStart
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class StadiumSingleBattle: StadiumBattleDefenition() {
|
||||
@JvmField
|
||||
val MAX_PLAYERS = 2
|
||||
|
||||
var player1Position = Vec3(0.0,0.0,0.0)
|
||||
var player2Position = Vec3(0.0,0.0,0.0)
|
||||
|
||||
var player1PokemonPosition = Vec3(0.0,0.0,0.0)
|
||||
var player2PokemonPosition = Vec3(0.0,0.0,0.0)
|
||||
|
||||
var activeBattle: PokemonBattle? = null
|
||||
|
||||
override fun readyForBattle(): Boolean {
|
||||
return this.getPlayers().count() == MAX_PLAYERS
|
||||
}
|
||||
|
||||
override fun canAddPlayer(player: ServerPlayer): Boolean {
|
||||
val party = player.party()
|
||||
return party.occupied() > 0
|
||||
}
|
||||
|
||||
override fun addPlayer(player: ServerPlayer) {
|
||||
if (canAddPlayer(player)) {
|
||||
participants.add(player.uuid)
|
||||
player.sendPacket(StadiumJoinPacket(player.uuid, StadiumCameraManagers.managers.keys.first()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPlayers(): MutableList<ServerPlayer> {
|
||||
return participants.mapNotNull { it.getPlayer() }.toMutableList()
|
||||
}
|
||||
|
||||
override fun initializeBattle() {
|
||||
if (!readyForBattle()) return
|
||||
|
||||
val players = getPlayers()
|
||||
|
||||
val player1 = players[0]
|
||||
val player2 = players[1]
|
||||
|
||||
val battleResult = BattleBuilder.pvp1v1(player1, player2)
|
||||
var errored = false
|
||||
battleResult.ifErrored { errored = true }
|
||||
if (errored) return
|
||||
|
||||
val battle = (battleResult as SuccessfulBattleStart).battle
|
||||
}
|
||||
|
||||
override fun getCurrentCamera(): StadiumCameraEntry {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.cobblemon.mod.common.util
|
||||
|
||||
import com.cobblemon.mod.common.util.math.geometry.toDegrees
|
||||
import com.cobblemon.mod.common.util.math.toEulerXYZ
|
||||
import net.minecraft.client.Camera
|
||||
import org.joml.Quaternionf
|
||||
|
||||
fun Camera.setRotation(pitch: Float, yaw: Float, roll: Float) {
|
||||
this.xRot = pitch.toDegrees()
|
||||
this.yRot = yaw.toDegrees()
|
||||
this.rotation.rotationYXZ(yaw, pitch, roll)
|
||||
Camera.FORWARDS.rotate(this.rotation, this.forwards)
|
||||
Camera.UP.rotate(this.rotation, this.up)
|
||||
Camera.LEFT.rotate(this.rotation, this.left)
|
||||
}
|
||||
+1
@@ -38,6 +38,7 @@ object RidingBehaviourSettingsAdapter : JsonDeserializer<RidingBehaviourSettings
|
||||
JetAirBehaviour.KEY to JetAirSettings::class.java,
|
||||
SwimDashBehaviour.KEY to SwimDashSettings::class.java,
|
||||
VehicleLandBehaviour.KEY to VehicleLandSettings::class.java,
|
||||
HoverBehaviour.KEY to HoverSettings::class.java,
|
||||
CompositeBehaviour.KEY to CompositeSettings::class.java,
|
||||
|
||||
/*
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"format_version": "1.8.0",
|
||||
"animations": {
|
||||
"animation.rotom_drone.sleep": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [
|
||||
"math.sin(query.anim_time * 120) * 6",
|
||||
0,
|
||||
"math.cos(query.anim_time * 100) * 4"
|
||||
],
|
||||
"position": [
|
||||
0,
|
||||
"18 + math.sin(query.anim_time * 90) * 1",
|
||||
0
|
||||
]
|
||||
},
|
||||
"head": {
|
||||
"relative_to": {
|
||||
"rotation": "entity"
|
||||
},
|
||||
"rotation": [
|
||||
0,
|
||||
0,
|
||||
0.01
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rotom_drone.circle": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"rotom_drone": {
|
||||
"rotation": [30, "90 - q.anim_time*90", 0],
|
||||
"position": ["48*math.cos(q.anim_time*90)", 64, "48*math.sin(q.anim_time*90)"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
{
|
||||
"format_version": "1.12.0",
|
||||
"minecraft:geometry": [
|
||||
{
|
||||
"description": {
|
||||
"identifier": "geometry.drone_rotom",
|
||||
"texture_width": 64,
|
||||
"texture_height": 32,
|
||||
"visible_bounds_width": 8,
|
||||
"visible_bounds_height": 6.5,
|
||||
"visible_bounds_offset": [0, 2.75, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
"name": "rotom_drone",
|
||||
"pivot": [0, 0, 0]
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"parent": "rotom_drone",
|
||||
"pivot": [0, 8, 0]
|
||||
},
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "body",
|
||||
"pivot": [0, 6.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-5.5, 6.5, -3.5], "size": [11, 6, 7], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eyes",
|
||||
"parent": "head",
|
||||
"pivot": [0.5, 6.5, -2.5]
|
||||
},
|
||||
{
|
||||
"name": "eye_right",
|
||||
"parent": "eyes",
|
||||
"pivot": [-2.9, 9.5, -3.5],
|
||||
"rotation": [0, 0, -7.5],
|
||||
"cubes": [
|
||||
{"origin": [-3.9, 7.5, -3.5], "size": [2, 4, 0], "inflate": 0.01, "uv": [0, 0], "mirror": true},
|
||||
{"origin": [-3.9, 9, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [0, 6], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pupil_right",
|
||||
"parent": "eye_right",
|
||||
"pivot": [-2.9, 9.5, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [-3.4, 8, -3.5], "size": [1, 3, 0], "inflate": 0.03, "uv": [5, 0], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye_left",
|
||||
"parent": "eyes",
|
||||
"pivot": [2.9, 9.5, -3.5],
|
||||
"rotation": [0, 0, 7.5],
|
||||
"cubes": [
|
||||
{"origin": [1.9, 7.5, -3.5], "size": [2, 4, 0], "inflate": 0.01, "uv": [0, 13]},
|
||||
{"origin": [1.9, 9, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [0, 5]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pupil_left",
|
||||
"parent": "eye_left",
|
||||
"pivot": [2.9, 9.5, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [2.4, 8, -3.5], "size": [1, 3, 0], "inflate": 0.03, "uv": [6, 13]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_smile",
|
||||
"parent": "head",
|
||||
"pivot": [0, 7.55, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [-1, 6.95, -3.5], "size": [2, 1, 0], "inflate": 0.02, "uv": [36, 7]},
|
||||
{"origin": [-1.5, 7.25, -3.5], "size": [1, 1, 0], "inflate": 0.01, "uv": [40, 7]},
|
||||
{"origin": [0.5, 7.25, -3.5], "size": [1, 1, 0], "inflate": 0.01, "uv": [42, 7]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_closed",
|
||||
"parent": "head",
|
||||
"pivot": [0, 7.45, -3.4],
|
||||
"cubes": [
|
||||
{"origin": [-0.5, 6.95, -3.4], "size": [1, 1, 0], "inflate": 0.02, "uv": [38, 8]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_open",
|
||||
"parent": "head",
|
||||
"pivot": [0, 7.45, -3.4],
|
||||
"cubes": [
|
||||
{"origin": [-0.5, 6.95, -3.4], "size": [1, 1, 0], "inflate": 0.02, "uv": [36, 8]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mouth_sad",
|
||||
"parent": "head",
|
||||
"pivot": [0, 7.6, -3.3],
|
||||
"cubes": [
|
||||
{"origin": [-1, 7.3, -3.3], "size": [2, 1, 0], "inflate": 0.02, "uv": [36, 9]},
|
||||
{"origin": [-1.5, 7, -3.3], "size": [1, 1, 0], "inflate": 0.01, "uv": [40, 9]},
|
||||
{"origin": [0.5, 7, -3.3], "size": [1, 1, 0], "inflate": 0.01, "uv": [42, 9]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "head_spike1",
|
||||
"parent": "head",
|
||||
"pivot": [0, 12.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, 11.5, -1.5], "size": [3, 4, 3], "uv": [29, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "head_spike2",
|
||||
"parent": "head_spike1",
|
||||
"pivot": [0, 15.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-1, 14.5, -1], "size": [2, 4, 2], "uv": [8, 13]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "head_spike3",
|
||||
"parent": "head_spike2",
|
||||
"pivot": [0, 18.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-0.5, 17.5, -0.5], "size": [1, 3, 1], "uv": [44, 6]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "torso",
|
||||
"parent": "body",
|
||||
"pivot": [0, 7, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, 3, -1.5], "size": [4, 4, 3], "uv": [34, 10]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "camera",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 4.65, -1.25],
|
||||
"cubes": [
|
||||
{"origin": [-1, 3.65, -2.75], "size": [2, 2, 2], "uv": [24, 13]},
|
||||
{"origin": [-0.5, 4.15, -2.75], "size": [1, 1, 0], "inflate": 0.01, "uv": [38, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "propeller_front_right",
|
||||
"parent": "torso",
|
||||
"pivot": [-1.5, 5, -1],
|
||||
"rotation": [0, 45, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, 5, -3.5], "size": [1, 0, 3], "uv": [37, 0]},
|
||||
{"origin": [-5.5, 5, -11.5], "size": [8, 0, 8], "uv": [40, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "propeller_front_left",
|
||||
"parent": "torso",
|
||||
"pivot": [1.5, 5, -1],
|
||||
"rotation": [0, -45, 0],
|
||||
"cubes": [
|
||||
{"origin": [1, 5, -3.5], "size": [1, 0, 3], "uv": [27, 0]},
|
||||
{"origin": [-2.5, 5, -11.5], "size": [8, 0, 8], "uv": [40, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "propeller_back_right",
|
||||
"parent": "torso",
|
||||
"pivot": [-1.5, 5, 1],
|
||||
"rotation": [0, -45, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, 5, 0.5], "size": [1, 0, 3], "uv": [39, 0]},
|
||||
{"origin": [-5.5, 5, 3.5], "size": [8, 0, 8], "uv": [40, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "propeller_back_left",
|
||||
"parent": "torso",
|
||||
"pivot": [1.5, 5, 1],
|
||||
"rotation": [0, 45, 0],
|
||||
"cubes": [
|
||||
{"origin": [1, 5, 0.5], "size": [1, 0, 3], "uv": [42, 3]},
|
||||
{"origin": [-2.5, 5, 3.5], "size": [8, 0, 8], "uv": [40, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail1",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 3, 0],
|
||||
"cubes": [
|
||||
{"origin": [-1, 1, -1], "size": [2, 3, 2], "uv": [16, 13]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail2",
|
||||
"parent": "tail1",
|
||||
"pivot": [0, 1, 0],
|
||||
"cubes": [
|
||||
{"origin": [-0.5, -1, -0.5], "size": [1, 3, 1], "uv": [41, 3]}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"poses": {
|
||||
"sleep": {
|
||||
"poseTypes": ["SLEEP"],
|
||||
"animations": ["q.bedrock('rotom_drone', 'sleep')"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "cobblemon:rotom_drone",
|
||||
"order": 0,
|
||||
"variations": [
|
||||
{
|
||||
"aspects": [],
|
||||
"poser": "cobblemon:rotom_drone",
|
||||
"model": "cobblemon:rotom_drone.geo",
|
||||
"texture": "cobblemon:textures/drone/rotom_drone.png",
|
||||
"layers": []
|
||||
}
|
||||
]
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"format_version": "1.8.0",
|
||||
"animations": {
|
||||
"animation.ride_test.sitting": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"position": [0, -9, 0]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [25, 0, 0]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [0, 0, 22.5]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [0, 0, -27.5]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": [-90, 20, 0]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": [-90, -20, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+488
-93
@@ -2272,23 +2272,59 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.4167": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"0.5833": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.0417": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"2.375": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"3.0": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"5.875": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"0.5833": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"2.375": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"3.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"5.875": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.4167": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"0.5833": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.0417": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"2.375": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"3.0": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"5.875": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"0.5833": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"2.375": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"3.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"5.875": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2553,15 +2589,27 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"1.25": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"3.6667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"3.6667": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"1.25": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"3.6667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"1.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"3.6667": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
@@ -8763,19 +8811,43 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"0.5": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.25": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"2.4583": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"2.4583": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"0.5": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.25": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"2.4583": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"2.4583": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11221,23 +11293,59 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"0.4167": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"0.8333": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"1.125": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.5417": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"2.6667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"0.4167": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"0.8333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"1.125": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"2.6667": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.25": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"0.4167": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"0.8333": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"1.125": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.5417": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"2.6667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"0.4167": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"0.8333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"1.125": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"2.6667": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"locator_target": {
|
||||
@@ -13529,19 +13637,43 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.3333": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"1.2083": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.5417": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"2.7083": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.3333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"1.2083": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"2.7083": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.3333": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"1.2083": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.5417": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"2.7083": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.3333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"1.2083": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"2.7083": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"locator_mouth": {
|
||||
@@ -13740,14 +13872,20 @@
|
||||
"position": {
|
||||
"0.0": [-0.1, 0.1, 0],
|
||||
"0.125": [-0.1, 0.1, 0],
|
||||
"0.1667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0.1, 0.1, 0],
|
||||
"0.125": [0.1, 0.1, 0],
|
||||
"0.1667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
@@ -14543,7 +14681,7 @@
|
||||
"rotation": [0, -6, -15]
|
||||
},
|
||||
"wing_right_elbow": {
|
||||
"rotation": [0, "-6", -15],
|
||||
"rotation": [0, "-6+", -15],
|
||||
"position": [0.45, 0.1, 0]
|
||||
},
|
||||
"wing_right_membrane": {
|
||||
@@ -16036,7 +16174,7 @@
|
||||
"animation_length": 4,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [22.5, 0, "math.sin(q.anim_time*90*1-90)*-0.5"],
|
||||
"rotation": ["22.5 + q.riding.pitch(0)*-90", 0, "math.sin(q.anim_time*90*1-90)*-0.5"],
|
||||
"position": ["math.cos(q.anim_time*90*1-60)*1", "12+math.cos((q.anim_time*90*2-60)+math.sin(q.anim_time*90*2)*20)*3", 0]
|
||||
},
|
||||
"torso": {
|
||||
@@ -17357,6 +17495,14 @@
|
||||
"locator_top": {
|
||||
"position": [0, 13, 0]
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"1.125": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
},
|
||||
"3.1667": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.charizard.air_fly": {
|
||||
@@ -18633,6 +18779,17 @@
|
||||
},
|
||||
"locator_top": {
|
||||
"position": [0, -1, 0]
|
||||
},
|
||||
"locator_seat_1": {
|
||||
"rotation": [-60, 0, 0]
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"1.0833": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
},
|
||||
"3.0833": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -18898,6 +19055,9 @@
|
||||
},
|
||||
"locator_top": {
|
||||
"position": [0, -6, 0]
|
||||
},
|
||||
"locator_seat_1": {
|
||||
"rotation": [-60, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -19097,23 +19257,59 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.4167": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"0.5833": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.4167": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"2.5833": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"3.9167": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"4.0833": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"0.5833": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"2.5833": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"3.9167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"4.0833": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.4167": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"0.5833": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.4167": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"2.5833": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"3.9167": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"4.0833": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"0.5833": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.4167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"2.5833": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"3.9167": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"4.0833": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22458,7 +22654,10 @@
|
||||
},
|
||||
"0.5": [0.78, -10.13, 0.45],
|
||||
"0.5417": [-0.45, -8.03, 0.45],
|
||||
"0.5833": {"pre": [-0.45, -8.03, 0.45], "post": [-0.45, "-7.79+360", 0.45]},
|
||||
"0.5833": {
|
||||
"pre": [-0.45, -8.03, 0.45],
|
||||
"post": [-0.45, "-7.79+360", 0.45]
|
||||
},
|
||||
"0.625": [-2.7, 355.37, 0.45],
|
||||
"1.0": {
|
||||
"pre": [-9.46, "10.71+360", 0.5],
|
||||
@@ -26129,23 +26328,59 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0833": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"0.3333": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"1.625": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"1.8333": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"2.625": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.0833": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.625": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"1.8333": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"2.625": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0833": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"0.3333": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"1.625": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"1.8333": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.5": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"2.625": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.0833": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"0.3333": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.625": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"1.8333": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"2.625": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"locator_root": {
|
||||
@@ -29385,9 +29620,15 @@
|
||||
"brow": {
|
||||
"position": {
|
||||
"0.9583": [0, 0, 0],
|
||||
"1.1667": {"pre": [0, 0, 0], "post": [0, 0, -0.3]},
|
||||
"1.1667": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.3]
|
||||
},
|
||||
"2.2917": [0, 0, -0.3],
|
||||
"2.5417": {"pre": [0, 0, -0.3], "post": [0, 0, 0]}
|
||||
"2.5417": {
|
||||
"pre": [0, 0, -0.3],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"jaw": {
|
||||
@@ -29722,19 +29963,43 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.3333": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"1.2083": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.375": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"2.6667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.3333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"1.2083": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"2.6667": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.3333": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"1.2083": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.375": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"2.6667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.3333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"1.2083": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"2.6667": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"locator_root": {
|
||||
@@ -29753,6 +30018,106 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.charizard.ride_air_look": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": ["q.riding.pitch_change(0)*-0", "q.riding.yaw_change(0)*-15", "q.riding.roll_change(0)*15"]
|
||||
},
|
||||
"neck": {
|
||||
"rotation": ["math.clamp(q.riding.pitch_change(0),-0.5,1.0)*-20", 0, "q.riding.yaw_change(0)*7"]
|
||||
},
|
||||
"neck2": {
|
||||
"rotation": ["math.clamp(q.riding.pitch_change(0),-0.5,1.0)*-12", 0, "q.riding.yaw_change(0)*12"]
|
||||
},
|
||||
"neck3": {
|
||||
"rotation": ["q.riding.pitch_change(0)*-7", 0, "q.riding.yaw_change(0)*7"]
|
||||
},
|
||||
"neck4": {
|
||||
"rotation": ["q.riding.pitch_change(0)*-7", 0, "q.riding.yaw_change(0)*7"]
|
||||
},
|
||||
"head_angle": {
|
||||
"rotation": ["q.riding.pitch_change(0)*-7", 0, "q.riding.yaw_change(0)*7"]
|
||||
},
|
||||
"shoulder_right": {
|
||||
"rotation": [0, "-12.5*q.riding.pitch_change(0)", "27.5*q.riding.yaw_change(0)"]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [0, "15*q.riding.yaw_change(0)", 0]
|
||||
},
|
||||
"forearm_right": {
|
||||
"rotation": [0, "15*q.riding.yaw_change(0)", "-12.5*q.riding.pitch_change(0)"]
|
||||
},
|
||||
"shoulder_left": {
|
||||
"rotation": [0, "12.5*q.riding.pitch_change(0)", "27.5*q.riding.yaw_change(0)"]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [0, "15*q.riding.yaw_change(0)", 0]
|
||||
},
|
||||
"forearm_left": {
|
||||
"rotation": [0, "15*q.riding.yaw_change(0)", "12.5*q.riding.pitch_change(0)"]
|
||||
},
|
||||
"wing_right_base": {
|
||||
"rotation": ["-5*q.riding.pitch_change(0)", 0, 0]
|
||||
},
|
||||
"wing_right_bend": {
|
||||
"rotation": ["10*q.riding.yaw_change(0)", "7.5*q.riding.pitch_change(0)", "10*q.riding.yaw_change(0)"]
|
||||
},
|
||||
"wing_right_mid": {
|
||||
"rotation": ["-5*q.riding.pitch_change(0)", 0, 0]
|
||||
},
|
||||
"wing_right_elbow": {
|
||||
"rotation": ["-2.5*q.riding.pitch_change(0)", "5*q.riding.pitch_change(0)", 0]
|
||||
},
|
||||
"wing_left_base": {
|
||||
"rotation": ["-5*q.riding.pitch_change(0)", 0, 0]
|
||||
},
|
||||
"wing_left_bend": {
|
||||
"rotation": ["-10*q.riding.yaw_change(0)", "-7.5*q.riding.pitch_change(0)", "-10*q.riding.yaw_change(0)"]
|
||||
},
|
||||
"wing_left_mid": {
|
||||
"rotation": ["-5*q.riding.pitch_change(0)", 0, 0]
|
||||
},
|
||||
"wing_left_elbow": {
|
||||
"rotation": ["-2.5*q.riding.pitch_change(0)", "-(5*q.riding.pitch_change(0))", 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": ["q.riding.pitch_change(0)*7", 0, "q.riding.yaw_change(0)*-10"]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": ["q.riding.pitch_change(0)*7", "q.riding.yaw_change(0)*15", 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": ["q.riding.pitch_change(0)*7", "q.riding.yaw_change(0)*20", 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": ["q.riding.pitch_change(0)*7", "q.riding.yaw_change(0)*20", 0]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": ["q.riding.pitch_change(0)*8", "q.riding.yaw_change(0)*20", 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": ["-12.5*q.riding.pitch_change(0)", "q.riding.yaw_change(0)*20", 0],
|
||||
"position": ["-1.5*q.riding.yaw_change(0)", 0, 0]
|
||||
},
|
||||
"knee_right": {
|
||||
"rotation": ["-12.5*q.riding.pitch_change(0)", 0, 0]
|
||||
},
|
||||
"foot_right": {
|
||||
"rotation": ["-12.5*q.riding.pitch_change(0)", 0, 0]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": ["-12.5*q.riding.pitch_change(0)", "q.riding.yaw_change(0)*20", 0],
|
||||
"position": ["-1.5*q.riding.yaw_change(0)", 0, 0]
|
||||
},
|
||||
"knee_left": {
|
||||
"rotation": ["-12.5*q.riding.pitch_change(0)", 0, 0]
|
||||
},
|
||||
"foot_left": {
|
||||
"rotation": ["-12.5*q.riding.pitch_change(0)", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.charizard.air_status": {
|
||||
"animation_length": 3,
|
||||
"bones": {
|
||||
@@ -32994,19 +33359,43 @@
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.3333": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"1.2083": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.2083": {"pre": [0, 0, 0], "post": [-0.1, 0.1, 0]},
|
||||
"2.4583": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.3333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"1.2083": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.2083": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [-0.1, 0.1, 0]
|
||||
},
|
||||
"2.4583": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.3333": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"1.2083": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]},
|
||||
"2.2083": {"pre": [0, 0, 0], "post": [0.1, 0.1, 0]},
|
||||
"2.4583": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.3333": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"1.2083": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.2083": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.1, 0.1, 0]
|
||||
},
|
||||
"2.4583": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"locator_root": {
|
||||
@@ -34432,14 +34821,20 @@
|
||||
"position": {
|
||||
"0.0": [-0.1, 0.1, 0],
|
||||
"0.125": [-0.1, 0.1, 0],
|
||||
"0.1667": {"pre": [-0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [-0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0.1, 0.1, 0],
|
||||
"0.125": [0.1, 0.1, 0],
|
||||
"0.1667": {"pre": [0.1, 0.1, 0], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0.1, 0.1, 0],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
@@ -535,6 +535,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.5": {
|
||||
"effect": "animation.plumage.wing_flap.medium"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.pidgeot.air_fly": {
|
||||
@@ -710,6 +715,9 @@
|
||||
},
|
||||
"wing_open_right4": {
|
||||
"rotation": [0, 0, "7.5+math.sin(q.anim_time*90*0.8-240)*-10+math.sin(q.anim_time*90*12-120)*0.4"]
|
||||
},
|
||||
"locator_seat1": {
|
||||
"position": [0, 1.5, -4]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1566,6 +1574,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"1.375": {
|
||||
"effect": "animation.plumage.wing_flap.medium"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.pidgeot.air_fly_quirk2": {
|
||||
@@ -2721,6 +2734,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"1.4583": {
|
||||
"effect": "animation.plumage.wing_flap.medium"
|
||||
},
|
||||
"3.0833": {
|
||||
"effect": "animation.plumage.wing_flap.medium"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.pidgeot.blink": {
|
||||
|
||||
+1480
-29
File diff suppressed because it is too large
Load Diff
+12
@@ -467,6 +467,7 @@
|
||||
},
|
||||
"animation.aerodactyl.air_idle": {
|
||||
"loop": true,
|
||||
"animation_length": 1.33333,
|
||||
"bones": {
|
||||
"aerodactyl": {
|
||||
"position": [0, 3, 0]
|
||||
@@ -642,10 +643,16 @@
|
||||
"right_wing_membrane": {
|
||||
"rotation": [0, "0+math.sin(q.anim_time*90*3+90)*3", "0+math.sin(q.anim_time*90*3+90)*1.5"]
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"1.0833": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.aerodactyl.air_fly": {
|
||||
"loop": true,
|
||||
"animation_length": 1.33333,
|
||||
"bones": {
|
||||
"aerodactyl": {
|
||||
"position": [0, 3, 0]
|
||||
@@ -827,6 +834,11 @@
|
||||
"right_horn": {
|
||||
"rotation": ["math.sin(q.anim_time*90*12-160)*2", 0, 0]
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.9583": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.aerodactyl.sleep": {
|
||||
|
||||
+97
@@ -1237,6 +1237,20 @@
|
||||
"rotation": ["-math.sin(q.anim_time*90*2-120)*4", 0, 0],
|
||||
"position": [0, "7.8+math.sin(q.anim_time*90*2)*2", -5.6]
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"1.5": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
},
|
||||
"3.5": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
},
|
||||
"5.5": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
},
|
||||
"7.5": {
|
||||
"effect": "animation.leather.wing_flap.medium"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dragonite.water_idle": {
|
||||
@@ -2053,6 +2067,89 @@
|
||||
"effect": "pokemon.dragonite.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dragonite.shock": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"pupil_left": {
|
||||
"scale": [0.7, 0.7, 1]
|
||||
},
|
||||
"eye_shine_left": {
|
||||
"position": [0, -0.5, 0]
|
||||
},
|
||||
"pupil_right": {
|
||||
"scale": [0.7, 0.7, 1]
|
||||
},
|
||||
"eye_shine_right": {
|
||||
"position": [0, -0.5, 0]
|
||||
},
|
||||
"jaw": {
|
||||
"rotation": [27.5, 0, 0]
|
||||
},
|
||||
"eye_left": {
|
||||
"position": [0, 0, 0],
|
||||
"scale": 1
|
||||
},
|
||||
"eye_shocked_left": {
|
||||
"position": [0.25, 0, -0.26]
|
||||
},
|
||||
"eye_shocked_right": {
|
||||
"position": [-0.125, 0, -0.18]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dragonite.angry": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_angry_left": {
|
||||
"position": [0.1, 0, -0.1]
|
||||
},
|
||||
"eye_shine_left": {
|
||||
"position": [0, -1, 0]
|
||||
},
|
||||
"eye_shine_right": {
|
||||
"position": [0, -1, 0]
|
||||
},
|
||||
"eye_angry_right": {
|
||||
"position": [-0.1, 0, -0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dragonite.sad": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eye_sad_left": {
|
||||
"position": [0.1, 0, -0.1]
|
||||
},
|
||||
"eye_sad_right": {
|
||||
"position": [-0.1, 0, -0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dragonite.happy": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eyelid_happy_left": {
|
||||
"position": [0.1, 0, -0.1]
|
||||
},
|
||||
"eyelid_happy_right": {
|
||||
"position": [-0.1, 0, -0.1]
|
||||
},
|
||||
"jaw": {
|
||||
"rotation": [27.5, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dragonite.hurt": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"eyelid_recoil_left": {
|
||||
"position": [0.1, 0, -0.1]
|
||||
},
|
||||
"eyelid_recoil_right": {
|
||||
"position": [-0.1, 0, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1077
-267
File diff suppressed because it is too large
Load Diff
+106
-26
@@ -5,7 +5,11 @@
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [0, "0 - Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5", "Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5"],
|
||||
"rotation": [
|
||||
"45*q.riding.velocity_forward(0)",
|
||||
"0 - Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5",
|
||||
"Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5 + 45*q.riding.velocity_right(0)"
|
||||
],
|
||||
"position": ["Math.Sin((q.anim_time * 180 * 0.5) * 1) * 1.5", "7+Math.Sin((q.anim_time * 90 * 0.5) * 1) * 1.5", 0]
|
||||
},
|
||||
"magnet_back_rotation": {
|
||||
@@ -45,7 +49,11 @@
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [15, "0 - Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5", "Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5"],
|
||||
"rotation": [
|
||||
"2.5 + 45*q.riding.velocity_forward(0)",
|
||||
"- Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5",
|
||||
"Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5 - 45*q.riding.velocity_right(0)"
|
||||
],
|
||||
"position": ["Math.Sin((q.anim_time * 180 * 0.5) * 1) * 1.5", "7+Math.Sin((q.anim_time * 90 * 0.5) * 1) * 1.5", 0]
|
||||
},
|
||||
"magnet_back_rotation": {
|
||||
@@ -266,45 +274,117 @@
|
||||
"pupil_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"0.5417": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"1.75": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
|
||||
"1.7917": {"pre": [0, 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, 0, 0.1]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"0.5417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.75": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"1.7917": {
|
||||
"pre": [0, 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, 0, 0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"pupil_closed_left": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.5": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"0.5417": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"1.75": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
|
||||
"1.7917": {"pre": [0, 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, 0, -0.1]}
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"0.5417": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"1.75": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"1.7917": {
|
||||
"pre": [0, 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, 0, -0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"pupil_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.2083": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"0.25": {"pre": [0, 0, 0], "post": [0, 0, 0.1]},
|
||||
"0.5": {"pre": [0, 0, 0.1], "post": [0, 0, 0.1]},
|
||||
"0.5417": {"pre": [0, 0, 0.1], "post": [0, 0, 0]},
|
||||
"1.9583": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"2.0": {"pre": [0, 0, 0], "post": [0, 0, 0.1]}
|
||||
"0.2083": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"0.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0.1]
|
||||
},
|
||||
"0.5417": {
|
||||
"pre": [0, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.9583": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"pupil_closed_right": {
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.2083": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"0.25": {"pre": [0, 0, 0], "post": [0, 0, -0.1]},
|
||||
"0.5": {"pre": [0, 0, -0.1], "post": [0, 0, -0.1]},
|
||||
"0.5417": {"pre": [0, 0, -0.1], "post": [0, 0, 0]},
|
||||
"1.9583": {"pre": [0, 0, 0], "post": [0, 0, 0]},
|
||||
"2.0": {"pre": [0, 0, 0], "post": [0, 0, -0.1]}
|
||||
"0.2083": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"0.25": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"0.5": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, -0.1]
|
||||
},
|
||||
"0.5417": {
|
||||
"pre": [0, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"1.9583": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, 0]
|
||||
},
|
||||
"2.0": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0, 0, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+8
-4
@@ -155,6 +155,9 @@
|
||||
"back_neck_braid_right4": {
|
||||
"rotation": [2.5, 0, -10],
|
||||
"position": [-0.5, 0, 0]
|
||||
},
|
||||
"body": {
|
||||
"rotation": ["q.riding.velocity_y(0)*-90", 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -650,7 +653,7 @@
|
||||
}
|
||||
},
|
||||
"neck2": {
|
||||
"rotation": ["5+math.sin(q.anim_time*90*4-60)*2", 0, 0]
|
||||
"rotation": ["5+math.sin(q.anim_time*90*4-60)*2 - math.pow(q.riding.yaw_change(0),2)*20", "q.riding.yaw_change(0)*-10", "q.riding.yaw_change(0)*10"]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": ["-7.5+math.sin(q.anim_time*90*4-90)*2", "math.sin(q.anim_time*90*2)*1", "math.sin(q.anim_time*90*2)*4"]
|
||||
@@ -677,7 +680,7 @@
|
||||
}
|
||||
},
|
||||
"neck": {
|
||||
"rotation": ["3+math.sin(q.anim_time*90*4-30)*1", 0, "math.sin(q.anim_time*90*2-30)*2"]
|
||||
"rotation": ["3+math.sin(q.anim_time*90*4-30)*1", "q.riding.yaw_change(0)*-10", "math.sin(q.anim_time*90*2-30)*2 + q.riding.yaw_change(0)*10"]
|
||||
},
|
||||
"front_neck_braid_left": {
|
||||
"rotation": ["5+math.sin(q.anim_time*90*4-60)*1", 0.5, 5]
|
||||
@@ -844,6 +847,7 @@
|
||||
"position": [-0.5, 0, 0]
|
||||
},
|
||||
"body": {
|
||||
"rotation": ["q.riding.velocity_y(0)*-90", 0, 0],
|
||||
"position": {
|
||||
"0.0": [0, 0, 0],
|
||||
"0.0417": [0, -0.25, 0],
|
||||
@@ -1257,7 +1261,7 @@
|
||||
}
|
||||
},
|
||||
"neck2": {
|
||||
"rotation": ["math.sin(q.anim_time*90*4-60)*4", 0, 0]
|
||||
"rotation": ["math.sin(q.anim_time*90*4-60)*4 - math.pow(q.riding.yaw_delta(0),2)*20", "q.riding.yaw_delta(0)*-10", "q.riding.yaw_delta(0)*10"]
|
||||
},
|
||||
"tail5": {
|
||||
"rotation": ["-10+math.sin(q.anim_time*90*4-100)*6", "math.sin(q.anim_time*90*4-40)*2", "math.sin(q.anim_time*90*4-20)*1"]
|
||||
@@ -1279,7 +1283,7 @@
|
||||
}
|
||||
},
|
||||
"neck": {
|
||||
"rotation": ["13+math.sin(q.anim_time*90*4-30)*7", 0, 0],
|
||||
"rotation": ["13+math.sin(q.anim_time*90*4-30)*7", "q.riding.yaw_delta(0)*-10", "q.riding.yaw_delta(0)*10"],
|
||||
"position": [0, 0, "-0.5+math.sin(q.anim_time*90*4-30)*0.2"]
|
||||
},
|
||||
"front_neck_braid_left": {
|
||||
|
||||
+10790
-206
File diff suppressed because it is too large
Load Diff
+14
-1
@@ -458,8 +458,21 @@
|
||||
"2.125": [0, -42.5, 0],
|
||||
"2.3333": [0, -47.5, 0]
|
||||
}
|
||||
},
|
||||
"locator_camera": {
|
||||
"relative_to": {
|
||||
"rotation": "entity"
|
||||
},
|
||||
"position": {
|
||||
"0.0": [-24, 12, -23],
|
||||
"0.91667": [20, 11, -15]
|
||||
},
|
||||
"rotation": {
|
||||
"0.0": [0, -145, 0],
|
||||
"0.91667": [0, -215, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-1
@@ -1343,6 +1343,27 @@
|
||||
"2.2083": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"2.3333": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"locator_camera": {
|
||||
"relative_to": {
|
||||
"rotation": "entity"
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0, 45, -42],
|
||||
"0.125": [0, 16, -42],
|
||||
"1.20833": [0, 16, -42],
|
||||
"1.41667": [0, 66, -26],
|
||||
"2.20833": [0, 72, -11],
|
||||
"2.33333": [0, 26, -37]
|
||||
},
|
||||
"rotation": {
|
||||
"0.0": [197.5, 2.5, -180],
|
||||
"0.125": [172.5, 2.5, -180],
|
||||
"1.20833": [172.5, 2.5, -180],
|
||||
"1.41667": [227.5, 2.5, -180],
|
||||
"2.20833": [245, 2.5, -180],
|
||||
"2.33333": [185, 2.5, -180]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
@@ -3632,6 +3653,27 @@
|
||||
"0.2083": {"pre": [0, 0, 0], "post": [-0.1, 0, -0.1]},
|
||||
"1.375": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"locator_camera": {
|
||||
"relative_to": {
|
||||
"rotation": "entity"
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0, 22, -44],
|
||||
"0.25": [-41, 22, -25],
|
||||
"1.20833": [-41, 22, -25],
|
||||
"1.45833": [40, 22, -28],
|
||||
"2": [40, 22, -28],
|
||||
"2.20833": [0, 22, -61]
|
||||
},
|
||||
"rotation": {
|
||||
"0.0": [0, 180, 0],
|
||||
"0.25": [0, 227.5, 0],
|
||||
"1.20833": [0, 227.5, 0],
|
||||
"1.45833": [0, 127.5, 0],
|
||||
"2": [0, 127.5, 0],
|
||||
"2.20833": [0, 180, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
@@ -5910,4 +5952,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10866
-3300
File diff suppressed because it is too large
Load Diff
+115
-148
@@ -7,8 +7,8 @@
|
||||
"texture_width": 256,
|
||||
"texture_height": 128,
|
||||
"visible_bounds_width": 10,
|
||||
"visible_bounds_height": 5,
|
||||
"visible_bounds_offset": [0, 1.5, 0]
|
||||
"visible_bounds_height": 6,
|
||||
"visible_bounds_offset": [0, 2, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
@@ -20,7 +20,7 @@
|
||||
"parent": "charizard",
|
||||
"pivot": [0, 0, -1],
|
||||
"locators": {
|
||||
"root": [0, 0, 0]
|
||||
"root": [0, 0, -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -28,7 +28,7 @@
|
||||
"parent": "charizard",
|
||||
"pivot": [0, 41, -1],
|
||||
"locators": {
|
||||
"top": [0, 41, 0]
|
||||
"top": [0, 41, -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -116,7 +116,8 @@
|
||||
{
|
||||
"name": "head_correction",
|
||||
"parent": "head",
|
||||
"pivot": [0, 43.5, -0.5]
|
||||
"pivot": [0, 43.5, -0.5],
|
||||
"rotation": [-95, 0, 0]
|
||||
},
|
||||
{
|
||||
"name": "head_ai",
|
||||
@@ -127,20 +128,15 @@
|
||||
"name": "head_angle",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 43.5, -0.5],
|
||||
"rotation": [95, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 41.5, -2], "size": [7, 7, 5], "uv": [48, 0]},
|
||||
{"origin": [-3.5, 41.5, -4], "size": [7, 4, 2], "uv": [95, 64]}
|
||||
{"origin": [-3.5, 41.5, -4], "size": [7, 4, 2], "uv": [95, 64]},
|
||||
{"origin": [-2.5, 48, -2], "size": [5, 5, 2], "inflate": 0.02, "uv": [37, 31]},
|
||||
{"origin": [-2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [-2, 52.51777, -2], "rotation": [45, 0, 15], "uv": [43, 42]},
|
||||
{"origin": [2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [2, 52.51777, -2], "rotation": [45, 0, -15], "uv": [41, 42]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_hat",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 45, 3],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"item_hat": [0, 45, 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_head",
|
||||
"parent": "head_angle",
|
||||
@@ -150,51 +146,59 @@
|
||||
"head": [0, 46.5, 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_face",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 53.75, -0.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"face": [0, 53.75, -0.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_face",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 48.5, 0.5],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"item_face": [0, 48.5, 0.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_mouth",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 45.75, -2],
|
||||
"pivot": [0, 48.75, -3],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"mouth": [0, 45.75, -2],
|
||||
"special": [0, 45.75, -2]
|
||||
"mouth": [0, 48.75, -3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eyes",
|
||||
"name": "locator_special_attack",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, -3.5, 1.5]
|
||||
"pivot": [0, 48.75, -3],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"special_attack": [0, 48.75, -3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 51.75, -2.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"jaw1": [0, 51.75, -2.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "brow",
|
||||
"parent": "eyes",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 48.275, 1.765],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 48.55, 1], "size": [5, 0, 1], "uv": [0, 14]},
|
||||
{"origin": [-3.5, 47.5, 1.53], "size": [7, 1, 1], "inflate": 0.04, "uv": [0, 12]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, -3.5, 1.5]
|
||||
},
|
||||
{
|
||||
"name": "locator_face",
|
||||
"parent": "eye",
|
||||
"pivot": [0, 53.75, -0.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"face": [0, 53.75, -0.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eye_right",
|
||||
"parent": "eyes",
|
||||
"parent": "eye",
|
||||
"pivot": [-2.75, 47.75, 0.875],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 47.5, 0], "size": [2, 1, 2], "inflate": 0.01, "uv": [106, 36]},
|
||||
@@ -222,7 +226,7 @@
|
||||
},
|
||||
{
|
||||
"name": "eye_left",
|
||||
"parent": "eyes",
|
||||
"parent": "eye",
|
||||
"pivot": [2.75, 47.75, 0.875],
|
||||
"cubes": [
|
||||
{"origin": [1.5, 47.5, 0], "size": [2, 1, 2], "inflate": 0.01, "uv": [44, 82]},
|
||||
@@ -251,91 +255,6 @@
|
||||
{"origin": [2.41, 46.4, 0.5], "size": [1, 1, 1], "inflate": 0.03, "uv": [39, 86]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "muzzle",
|
||||
"parent": "head_angle",
|
||||
"pivot": [-3, 48.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 48, -2], "size": [5, 5, 2], "inflate": 0.02, "uv": [37, 31]},
|
||||
{"origin": [-2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [-2, 52.51777, -2], "rotation": [45, 0, 15], "uv": [43, 42]},
|
||||
{"origin": [2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [2, 52.51777, -2], "rotation": [45, 0, -15], "uv": [41, 42]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "muzzle",
|
||||
"pivot": [0, 51.75, -2.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"jaw1": [0, 51.75, -2.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nose",
|
||||
"parent": "muzzle",
|
||||
"pivot": [0, 53, 0],
|
||||
"rotation": [-40, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 51.36698, -1.67861], "size": [5, 2, 2], "inflate": 0.03, "uv": [48, 12]},
|
||||
{"origin": [-2, 53.40698, -1.17861], "size": [4, 0, 1], "uv": [0, 15]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 45.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 45.5, -4], "size": [7, 3, 2], "inflate": 0.01, "uv": [76, 20]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw2",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 48.5, -4],
|
||||
"rotation": [-7.5, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, 48.49, -4], "size": [4, 4, 2], "uv": [0, 51]},
|
||||
{"origin": [-1.5, 48.5, -2], "size": [3, 4, 0], "uv": [90, 0]},
|
||||
{"origin": [1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [1.5, 52.52782, -2], "rotation": [45, 0, -7.5], "uv": [37, 39]},
|
||||
{"origin": [-1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [-1.5, 52.52782, -2], "rotation": [45, 0, 7.5], "uv": [37, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw2",
|
||||
"pivot": [0, 51.75, -1.75],
|
||||
"locators": {
|
||||
"jaw2": {
|
||||
"offset": [0, 51.75, -1.75],
|
||||
"rotation": [-90, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tongue",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 45.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, 45.5, -2], "size": [3, 3, 0], "uv": [87, 29]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tongue2",
|
||||
"parent": "tongue",
|
||||
"pivot": [0, 48.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1, 48.5, -2], "size": [2, 2, 0], "inflate": 0.01, "uv": [46, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tongue3",
|
||||
"parent": "tongue2",
|
||||
"pivot": [0, 50.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1, 50.5, -2], "size": [2, 1, 0], "uv": [37, 43]},
|
||||
{"origin": [-0.5, 51.5, -2], "size": [1, 1, 0], "uv": [45, 43]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "horns",
|
||||
"parent": "head_angle",
|
||||
@@ -381,6 +300,72 @@
|
||||
"horn2": [2.5, 39, 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nose",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 53, 0],
|
||||
"rotation": [-40, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 51.36698, -1.67861], "size": [5, 2, 2], "inflate": 0.03, "uv": [48, 12]},
|
||||
{"origin": [-2, 53.40698, -1.17861], "size": [4, 0, 1], "uv": [0, 15]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 45.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 45.5, -4], "size": [7, 3, 2], "inflate": 0.01, "uv": [76, 20]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw2",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 48.5, -4],
|
||||
"rotation": [-7.5, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, 48.49, -4], "size": [4, 4, 2], "uv": [0, 51]},
|
||||
{"origin": [-1.5, 48.5, -1.99], "size": [3, 4, 0], "uv": [90, 0]},
|
||||
{"origin": [1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [1.5, 52.52782, -2], "rotation": [45, 0, -7.5], "uv": [37, 39]},
|
||||
{"origin": [-1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [-1.5, 52.52782, -2], "rotation": [45, 0, 7.5], "uv": [37, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw2",
|
||||
"pivot": [0, 51.75, -1.75],
|
||||
"locators": {
|
||||
"jaw2": {
|
||||
"offset": [0, 51.75, -1.75],
|
||||
"rotation": [-90, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tongue",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 45.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, 45.5, -2], "size": [3, 3, 0], "uv": [87, 29]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tongue2",
|
||||
"parent": "tongue",
|
||||
"pivot": [0, 48.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1, 48.5, -2], "size": [2, 2, 0], "inflate": 0.01, "uv": [46, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tongue3",
|
||||
"parent": "tongue2",
|
||||
"pivot": [0, 50.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1, 50.5, -2], "size": [2, 1, 0], "uv": [37, 43]},
|
||||
{"origin": [-0.5, 51.5, -2], "size": [1, 1, 0], "uv": [45, 43]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arms",
|
||||
"parent": "torso2",
|
||||
@@ -418,14 +403,6 @@
|
||||
{"origin": [-21.5, 22, -1.5], "size": [3, 2, 3], "inflate": 0.1, "uv": [0, 58]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_item",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-21.6, 23, 0],
|
||||
"locators": {
|
||||
"item": [-21.6, 23, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_hand_primary",
|
||||
"parent": "hand_right",
|
||||
@@ -936,14 +913,6 @@
|
||||
{"origin": [0, 9.5, 58.5], "size": [0, 13, 7], "pivot": [0, 14.45, 62], "rotation": [0, 90, 0], "uv": [0, 92]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_fire",
|
||||
"parent": "fire2",
|
||||
"pivot": [0, 11, 62],
|
||||
"locators": {
|
||||
"fire": [0, 11, 62]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "legs",
|
||||
"parent": "body",
|
||||
@@ -976,10 +945,9 @@
|
||||
{
|
||||
"name": "locator_foot_primary",
|
||||
"parent": "foot_right",
|
||||
"pivot": [-9, 1.5, -5],
|
||||
"rotation": [90, 0, 0],
|
||||
"pivot": [-9, 1.5, -7],
|
||||
"locators": {
|
||||
"foot_primary": [-9, 1.5, -5]
|
||||
"foot_primary": [-9, 1.5, -7]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1041,10 +1009,9 @@
|
||||
{
|
||||
"name": "locator_foot_secondary",
|
||||
"parent": "foot_left",
|
||||
"pivot": [9, 1.5, -5],
|
||||
"rotation": [90, 0, 0],
|
||||
"pivot": [9, 1.5, -7],
|
||||
"locators": {
|
||||
"foot_secondary": [9, 1.5, -5]
|
||||
"foot_secondary": [9, 1.5, -7]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+1100
-152
File diff suppressed because it is too large
Load Diff
+8
@@ -405,6 +405,14 @@
|
||||
"cubes": [
|
||||
{"origin": [-5, 6.5, 25.92], "size": [10, 3, 0], "uv": [77, 7]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_seat_1",
|
||||
"parent": "body",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
"seat_1": [0, 17.5, 4]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+10
-2
@@ -7,8 +7,8 @@
|
||||
"texture_width": 128,
|
||||
"texture_height": 128,
|
||||
"visible_bounds_width": 6,
|
||||
"visible_bounds_height": 4.5,
|
||||
"visible_bounds_offset": [0, 1.75, 0]
|
||||
"visible_bounds_height": 5,
|
||||
"visible_bounds_offset": [0, 1.5, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
@@ -480,6 +480,14 @@
|
||||
{"origin": [-4.5, 24.5, 26.5], "size": [9, 9, 7], "uv": [66, 109]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_seat_1",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
"seat_1": [0, 30, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "legs",
|
||||
"parent": "body",
|
||||
|
||||
+554
-445
File diff suppressed because it is too large
Load Diff
+9
-1
@@ -237,8 +237,16 @@
|
||||
"cubes": [
|
||||
{"origin": [10, 2, -1], "size": [2, 2, 2], "inflate": -0.001, "uv": [8, 36]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_camera",
|
||||
"parent": "tandemaus",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
"camera": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -601,8 +601,16 @@
|
||||
"cubes": [
|
||||
{"origin": [-2.33, -1, -2.65], "size": [2, 2, 2], "inflate": 0.02, "pivot": [-1.3, 0, -1.65], "rotation": [0, -45, 0], "uv": [52, 36], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_camera",
|
||||
"parent": "ceruledge",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
"camera": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+22
-4
@@ -26,8 +26,13 @@
|
||||
"pivot": [0, 4, 0]
|
||||
},
|
||||
{
|
||||
"name": "arm_hammer_right",
|
||||
"name": "arms_hammer",
|
||||
"parent": "torso_hammer",
|
||||
"pivot": [0, 7, 0]
|
||||
},
|
||||
{
|
||||
"name": "arm_hammer_right",
|
||||
"parent": "arms_hammer",
|
||||
"pivot": [-1.5, 6.5, 0]
|
||||
},
|
||||
{
|
||||
@@ -307,8 +312,13 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arm_left",
|
||||
"name": "arms",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 7, 0]
|
||||
},
|
||||
{
|
||||
"name": "arm_left",
|
||||
"parent": "arms",
|
||||
"pivot": [1.5, 6.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [1.5, 5.5, -1.5], "size": [3, 2, 3], "uv": [94, 16]}
|
||||
@@ -369,7 +379,7 @@
|
||||
},
|
||||
{
|
||||
"name": "arm_right",
|
||||
"parent": "torso",
|
||||
"parent": "arms",
|
||||
"pivot": [-1.5, 6.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-4.5, 5.5, -1.5], "size": [3, 2, 3], "uv": [58, 93]}
|
||||
@@ -459,8 +469,16 @@
|
||||
"cubes": [
|
||||
{"origin": [0.25, 0, -1], "size": [2, 2, 2], "inflate": 0.2, "uv": [38, 54]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_camera",
|
||||
"parent": "tinkaton",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
"camera": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+16
-2
@@ -99,7 +99,14 @@
|
||||
"poseTypes": ["FLY"],
|
||||
"isBattle": false,
|
||||
"condition": "!q.is_gliding",
|
||||
"animations": ["q.look('head_ai')", "q.bedrock('charizard', 'air_fly')"],
|
||||
"animations": [
|
||||
"q.look('head_ai')",
|
||||
"q.bedrock('charizard', 'air_fly')",
|
||||
{
|
||||
"condition": "q.is_ridden",
|
||||
"animation": "q.bedrock('charizard', 'ride_air_look')"
|
||||
}
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('charizard', 'blink')",
|
||||
"q.bedrock_quirk('charizard', 'air_fly_quirk')"
|
||||
@@ -109,7 +116,14 @@
|
||||
"poseTypes": ["FLY"],
|
||||
"isBattle": false,
|
||||
"condition": "q.is_gliding",
|
||||
"animations": ["q.look('head_ai')", "q.bedrock('charizard', 'air_glide_TEST')"],
|
||||
"animations": [
|
||||
"q.look('head_ai')",
|
||||
"q.bedrock('charizard', 'air_glide_TEST')",
|
||||
{
|
||||
"condition": "q.is_ridden",
|
||||
"animation": "q.bedrock('charizard', 'ride_air_look')"
|
||||
}
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('charizard', 'blink')"
|
||||
]
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"portraitScale": 0.89,
|
||||
"portraitTranslation": [-0.17,2.04,0],
|
||||
"profileScale": 0.37,
|
||||
"profileTranslation": [0,1.14,0],
|
||||
"rootBone": "kangaskhan",
|
||||
"animations": {
|
||||
"cry": "q.bedrock_stateful('kangaskhan', 'cry')",
|
||||
"recoil": "q.bedrock_stateful('kangaskhan', 'recoil')"
|
||||
},
|
||||
"poses": {
|
||||
"battle-standing": {
|
||||
"poseTypes": [
|
||||
"STAND"
|
||||
],
|
||||
"isBattle": true,
|
||||
"animations": [
|
||||
"q.look('kid_head')",
|
||||
"q.bedrock('kangaskhan', 'battle_idle')"
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('kangaskhan', 'blink')"
|
||||
]
|
||||
},
|
||||
"standing": {
|
||||
"poseTypes": [
|
||||
"STAND",
|
||||
"NONE",
|
||||
"PORTRAIT",
|
||||
"PROFILE"
|
||||
],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('kid_head')",
|
||||
"q.bedrock('kangaskhan', 'ground_idle')"
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('kangaskhan', 'blink')"
|
||||
]
|
||||
},
|
||||
"walking": {
|
||||
"poseTypes": [
|
||||
"WALK",
|
||||
"SWIM"
|
||||
],
|
||||
"animations": [
|
||||
"q.look('kid_head')",
|
||||
"q.bedrock('kangaskhan', 'ground_walk')"
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('kangaskhan', 'blink')"
|
||||
]
|
||||
},
|
||||
"sleep": {
|
||||
"poseTypes": [
|
||||
"SLEEP"
|
||||
],
|
||||
"animations": [
|
||||
"q.bedrock('kangaskhan', 'sleep')"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -4,6 +4,18 @@
|
||||
"profileScale": 0.28,
|
||||
"profileTranslation": [ 0, 1.26, 0 ],
|
||||
"rootBone": "tropius",
|
||||
"seatToCameraOffset": {
|
||||
"seat_1": [
|
||||
0,
|
||||
5,
|
||||
10
|
||||
],
|
||||
"seat_1_reverse": [
|
||||
0,
|
||||
2,
|
||||
4
|
||||
]
|
||||
},
|
||||
"animations": {
|
||||
"faint": "q.bedrock_primary('tropius', 'faint', q.curve('one'))",
|
||||
"cry": "q.bedrock_stateful('tropius', 'cry')",
|
||||
|
||||
+1
-2
@@ -139,8 +139,7 @@
|
||||
"poseTypes": ["FLY"],
|
||||
"animations": ["q.look('head')", "q.bedrock('garchomp', 'air_fly')"],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('garchomp', 'blink')",
|
||||
"q.bedrock_quirk('garchomp', q.array('air_fly_quirk1', 'air_fly_quirk2'), 5, 10, 1)"
|
||||
"q.bedrock_quirk('garchomp', 'blink')"
|
||||
],
|
||||
"transformedParts": [
|
||||
{
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"portraitScale": 1.5,
|
||||
"portraitTranslation": [-1.0, 1.76, 0.0],
|
||||
"profileScale": 0.5,
|
||||
"profileTranslation": [0.0, 1.0, 0.0],
|
||||
"rootBone": "mudsdale",
|
||||
"animations": {
|
||||
"cry": "q.bedrock_stateful('mudsdale', 'cry')"
|
||||
},
|
||||
"poses": {
|
||||
"sleep": {
|
||||
"poseName": "sleep",
|
||||
"poseTypes": ["SLEEP"],
|
||||
"animations": ["q.bedrock('mudsdale', 'sleep')"]
|
||||
},
|
||||
"standing": {
|
||||
"poseName": "standing",
|
||||
"poseTypes": ["STAND", "FLOAT", "NONE", "PORTRAIT", "PROFILE"],
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('mudsdale', 'ground_idle')",
|
||||
"q.bedrock_stateful('mudsdale', 'blink')"
|
||||
]
|
||||
},
|
||||
"walk": {
|
||||
"poseName": "walk",
|
||||
"poseTypes": ["WALK", "SWIM"],
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('mudsdale', 'ground_walk')",
|
||||
"q.bedrock_stateful('mudsdale', 'blink')"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+55
-25
@@ -1,28 +1,58 @@
|
||||
{
|
||||
"portraitScale": 1.7,
|
||||
"portraitTranslation": [-0.07, 2.95, 0],
|
||||
"profileScale": 0.33,
|
||||
"profileTranslation": [0, 1.23, 0],
|
||||
"rootBone": "cinderace",
|
||||
"animations": {
|
||||
"cry": "q.bedrock_stateful('cinderace', 'cry')"
|
||||
},
|
||||
"poses": {
|
||||
"standing": {
|
||||
"poseName": "standing",
|
||||
"poseTypes": ["STAND", "FLOAT", "PORTRAIT", "PROFILE", "NONE"],
|
||||
"animations": ["q.bedrock('cinderace', 'ground_idle')"],
|
||||
"quirks": ["q.bedrock_quirk('cinderace', 'blink')"]
|
||||
"portraitScale": 1.5,
|
||||
"portraitTranslation": [-0.13, 2.74, 0],
|
||||
"profileScale": 0.37,
|
||||
"profileTranslation": [0, 1.22, 0],
|
||||
"rootBone": "cinderace",
|
||||
"animations": {
|
||||
"faint": "q.bedrock_primary('cinderace', math.random(0, 1) < 0.25 ? 'faint2' : 'faint', q.curve('one'))",
|
||||
"cry": "q.bedrock_stateful('cinderace', 'cry')",
|
||||
"recoil": "q.bedrock_stateful('cinderace', 'recoil')",
|
||||
"physical": "q.bedrock_primary('cinderace', 'physical', q.curve('symmetrical'))",
|
||||
"special": "q.bedrock_primary('cinderace', 'special', q.curve('symmetrical'))",
|
||||
"status": "q.bedrock_primary('cinderace', 'status', q.curve('symmetrical'))"
|
||||
},
|
||||
"walking": {
|
||||
"poseName": "walking",
|
||||
"poseTypes": ["WALK", "SWIM"],
|
||||
"animations": [
|
||||
"q.bedrock('cinderace', 'ground_idle')",
|
||||
"q.biped_walk(0.66, 0.6, 'leg_left0', 'leg_right0')",
|
||||
"q.bimanual_swing(0.66, 0.6, 'arm_left', 'arm_right')"
|
||||
],
|
||||
"quirks": ["q.bedrock_quirk('cinderace', 'blink')"]
|
||||
"poses": {
|
||||
"battle-standing": {
|
||||
"poseTypes": ["STAND"],
|
||||
"isBattle": true,
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('cinderace', 'battle_idle')"
|
||||
],
|
||||
"namedAnimations": {
|
||||
"cry": "q.bedrock_primary('cinderace', 'battle_cry', q.curve('one'))"
|
||||
},
|
||||
"quirks": ["q.bedrock_quirk('cinderace', 'blink')"]
|
||||
},
|
||||
"standing": {
|
||||
"poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('cinderace', 'ground_idle')"
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('cinderace', 'blink')"
|
||||
],
|
||||
"transitions": {
|
||||
"battle-standing": "q.bedrock_primary('cinderace', 'battle_intro'), q.curve('symmetrical'))"
|
||||
}
|
||||
},
|
||||
"walking": {
|
||||
"poseTypes": ["WALK"],
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('cinderace', 'ground_walk')"
|
||||
],
|
||||
"quirks": ["q.bedrock_quirk('cinderace', 'blink')"]
|
||||
},
|
||||
"sleeping": {
|
||||
"poseTypes": ["SLEEP"],
|
||||
"namedAnimations": {
|
||||
"cry": "q.bedrock_stateful('dummy', 'cry')"
|
||||
},
|
||||
"animations": ["q.bedrock('cinderace', 'sleep')"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-16
@@ -1,17 +1,19 @@
|
||||
{
|
||||
"species": "cobblemon:kangaskhan",
|
||||
"order": 0,
|
||||
"variations": [
|
||||
{
|
||||
"aspects": [],
|
||||
"poser": "cobblemon:kangaskhan",
|
||||
"model": "cobblemon:kangaskhan.geo",
|
||||
"texture": "cobblemon:textures/pokemon/0115_kangaskhan/kangaskhan.png",
|
||||
"layers": []
|
||||
},
|
||||
{
|
||||
"aspects": ["shiny"],
|
||||
"texture": "cobblemon:textures/pokemon/0115_kangaskhan/kangaskhan_shiny.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
"species": "cobblemon:kangaskhan",
|
||||
"order": 0,
|
||||
"variations": [
|
||||
{
|
||||
"aspects": [],
|
||||
"poser": "cobblemon:kangaskhan",
|
||||
"model": "cobblemon:kangaskhan.geo",
|
||||
"texture": "cobblemon:textures/pokemon/0115_kangaskhan/kangaskhan.png",
|
||||
"layers": []
|
||||
},
|
||||
{
|
||||
"aspects": [
|
||||
"shiny"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0115_kangaskhan/kangaskhan_shiny.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
+12
-3
@@ -7,11 +7,20 @@
|
||||
"poser": "cobblemon:cinderace",
|
||||
"model": "cobblemon:cinderace.geo",
|
||||
"texture": "cobblemon:textures/pokemon/0815_cinderace/cinderace.png",
|
||||
"layers": []
|
||||
"layers": [
|
||||
{
|
||||
"name": "emissive",
|
||||
"emissive": true,
|
||||
"texture": "cobblemon:textures/pokemon/0815_cinderace/cinderace_emissive.png",
|
||||
"translucent": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["shiny"],
|
||||
"aspects": [
|
||||
"shiny"
|
||||
],
|
||||
"texture": "cobblemon:textures/pokemon/0815_cinderace/cinderace_shiny.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/stadium_terminal"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:block/cube_all",
|
||||
"textures": {
|
||||
"all": "cobblemon:block/stadium_terminal"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"parent": "cobblemon:block/stadium_terminal"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "cobblemon:item/evolution/syrupy_apple"
|
||||
}
|
||||
}
|
||||
@@ -1026,6 +1026,50 @@
|
||||
{ "name": "cobblemon:shiny/wild_shiny_ambient_chime_4", "volume": 0.8, "attenuation_distance": 128.0 }
|
||||
]
|
||||
},
|
||||
"animation.plumage.wing_flap.small": {
|
||||
"sounds": [
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_1", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_2", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_3", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_4", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_5", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_6", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_small_7", "volume": 0.25 }
|
||||
]
|
||||
},
|
||||
"animation.plumage.wing_flap.medium": {
|
||||
"sounds": [
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_1", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_2", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_3", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_4", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_5", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_6", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/plumage_wing_flap_medium_7", "volume": 0.3 }
|
||||
]
|
||||
},
|
||||
"animation.leather.wing_flap.small": {
|
||||
"sounds": [
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_1", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_2", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_3", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_4", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_5", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_6", "volume": 0.25 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_small_7", "volume": 0.25 }
|
||||
]
|
||||
},
|
||||
"animation.leather.wing_flap.medium": {
|
||||
"sounds": [
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_1", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_2", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_3", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_4", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_5", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_6", "volume": 0.3 },
|
||||
{ "name": "cobblemon:animation/wings/leather_wing_flap_medium_7", "volume": 0.3 }
|
||||
]
|
||||
},
|
||||
"pokemon.bulbasaur.ambient": {
|
||||
"sounds": [ "cobblemon:pokemon/bulbasaur/bulbasaur_ambient" ]
|
||||
},
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user