mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-24 08:06:24 -04:00
Compare commits
50
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3061ad2cfd | ||
|
|
5e04465970 | ||
|
|
9f0afd05ea | ||
|
|
702a670028 | ||
|
|
b9a8ed15d0 | ||
|
|
2413981f6f | ||
|
|
4ac244003a | ||
|
|
9ac92a084f | ||
|
|
aacbcb1f28 | ||
|
|
39ff7e418c | ||
|
|
58498a091d | ||
|
|
a806f77aff | ||
|
|
60ae9e3a55 | ||
|
|
c8f110cce8 | ||
|
|
4910350fd8 | ||
|
|
4bfe147730 | ||
|
|
963614f5fa | ||
|
|
7fdb70e3c3 | ||
|
|
f316dc7f6f | ||
|
|
1d412b2656 | ||
|
|
53d93d1c7c | ||
|
|
37e8f0eab6 | ||
|
|
05edafa5c4 | ||
|
|
cea600617e | ||
|
|
41ea22f58f | ||
|
|
666f339561 | ||
|
|
104eb4d825 | ||
|
|
8a15770f33 | ||
|
|
9e29b4f4f8 | ||
|
|
308c9d61c6 | ||
|
|
07ad22608d | ||
|
|
b50f924ce0 | ||
|
|
c0b55ebb6f | ||
|
|
cdc0a790fb | ||
|
|
13e8084f0d | ||
|
|
3daa3d31a3 | ||
|
|
585371bb08 | ||
|
|
aee97ff96e | ||
|
|
fbbd450d0d | ||
|
|
83612b50fc | ||
|
|
434faea210 | ||
|
|
6e24ee6b4e | ||
|
|
3d6a3fbfec | ||
|
|
708b810e6b | ||
|
|
509016e133 | ||
|
|
690183b994 | ||
|
|
33d56124f5 | ||
|
|
a5a65abe2b | ||
|
|
f73ab3b001 | ||
|
|
9a571984db |
@@ -17,6 +17,7 @@
|
||||
- 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`.
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
@@ -71,6 +72,7 @@
|
||||
- Added `interpolate` boolean property to animated textures to allow gradual colour changes between frames.
|
||||
- Fixed species additions not being capable of changing implemented status.
|
||||
- Added support for action effects that are triggered by `|-activate|` Showdown instructions. `activate_{effect_id}` is the syntax.
|
||||
- Added Molang functions for rendering items `render_item(item_id, locator_name)` and `clear_items()`.
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.RidingAltPose
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
@@ -71,6 +72,8 @@ import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
||||
import com.cobblemon.mod.common.pokemon.riding.controllers.BirdAirController
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.BirdAirState
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.mojang.datafixers.util.Either
|
||||
import java.util.UUID
|
||||
@@ -506,6 +509,7 @@ object MoLangFunctions {
|
||||
map.put("world") { _ -> entity.level().worldRegistry.wrapAsHolder(entity.level()).asWorldMoLangValue() }
|
||||
map.put("biome") { _ -> entity.level().getBiome(entity.blockPosition()).asBiomeMoLangValue() }
|
||||
map.put("is_passenger") { DoubleValue(entity.isPassenger) }
|
||||
map.put("has_passenger") { DoubleValue(entity.passengers.size > 0) }
|
||||
map.put("find_nearby_block") { params ->
|
||||
val type = params.getString(0).asIdentifierDefaultingNamespace(namespace = "minecraft")
|
||||
val isTag = type.path.startsWith("#")
|
||||
@@ -786,6 +790,17 @@ object MoLangFunctions {
|
||||
map.put("in_battle") { DoubleValue(pokemonEntity.isBattling) }
|
||||
map.put("is_moving") { DoubleValue((pokemonEntity.moveControl as? PokemonMoveControl)?.hasWanted() == true) }
|
||||
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
|
||||
map.put("riding_alt_pose") { params ->
|
||||
val poseName = params.getString(0).uppercase()
|
||||
val targetPose = RidingAltPose.fromString(poseName)
|
||||
if (targetPose == null) {
|
||||
//Invalid pose name
|
||||
DoubleValue(0.0)
|
||||
} else {
|
||||
val currentPose = pokemonEntity.getActiveRidingAltPose()
|
||||
DoubleValue(if (currentPose == targetPose) 1.0 else 0.0)
|
||||
}
|
||||
}
|
||||
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).isEmpty) }
|
||||
|
||||
@@ -13,13 +13,17 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.RidingAltPose
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.riding.util.Vec3Spring
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.toProperties
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.authlib.minecraft.client.MinecraftClient
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -32,6 +36,16 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
var lastSpeed = 0F
|
||||
var states: MutableMap<ResourceLocation, RidingState> = mutableMapOf()
|
||||
var deltaRotation = Vec2.ZERO
|
||||
var deltaRotationPerSec = Vec2.ZERO
|
||||
|
||||
//Riding animation data
|
||||
var prevRotation = Vec3.ZERO
|
||||
var rotSpring = Vec3Spring()
|
||||
var rotDeltaSpring = Vec3Spring()
|
||||
var velSpring = Vec3Spring()
|
||||
val stiffness = 90.0
|
||||
val damping = 19.0
|
||||
|
||||
|
||||
val runtime: MoLangRuntime by lazy {
|
||||
MoLangRuntime()
|
||||
@@ -77,12 +91,28 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
|
||||
val pose = controller.pose(entity)
|
||||
entity.entityData.set(PokemonEntity.POSE_TYPE, pose)
|
||||
//val speedPlayer = driver.deltaMovement.horizontalDistance()
|
||||
//driver.displayClientMessage(Component.literal("Speed player: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("$speedPlayer b/t")), true)
|
||||
//val speedEntity = entity.deltaMovement.length() //* 20 * 60 * 60) / ( 1000 )
|
||||
//println(speedEntity)
|
||||
//driver.displayClientMessage(Component.literal("Speed: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("${String.format("%.2f", speedEntity)} km/h")), true)
|
||||
|
||||
|
||||
// maybe here I do the required updates for riding animation stuff.
|
||||
val rollable = driver as? Rollable ?: return
|
||||
|
||||
val r = this.shouldRoll(entity)
|
||||
val currYaw = if(r) rollable.yaw else entity.yRot
|
||||
val currPitch = if(r) rollable.pitch else entity.xRot
|
||||
val currRoll = rollable.roll
|
||||
|
||||
|
||||
val angDelta = Vec3(
|
||||
Mth.degreesDifference(currPitch.toFloat(), prevRotation.x.toFloat()).toDouble(),
|
||||
Mth.degreesDifference(currYaw.toFloat(), prevRotation.y.toFloat()).toDouble(),
|
||||
Mth.degreesDifference(currRoll.toFloat(), prevRotation.z.toFloat()).toDouble()
|
||||
)
|
||||
|
||||
rotSpring.update(Vec3(currPitch.toDouble(), currYaw.toDouble(), currRoll.toDouble()), stiffness, damping)
|
||||
|
||||
rotDeltaSpring.update( angDelta, stiffness, damping)
|
||||
|
||||
prevRotation = Vec3(currPitch.toDouble(), currYaw .toDouble(), currRoll.toDouble())
|
||||
|
||||
}
|
||||
|
||||
fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
@@ -96,6 +126,8 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
val previousRotation = entity.rotationVector
|
||||
val rotation = controller.rotation(entity, driver)
|
||||
this.deltaRotation = Vec2(rotation.x - previousRotation.x, rotation.y - previousRotation.y)
|
||||
|
||||
this.deltaRotationPerSec = deltaRotation.scale(20.0f)
|
||||
return rotation
|
||||
}
|
||||
|
||||
@@ -111,6 +143,8 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
|
||||
fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3.ZERO
|
||||
|
||||
this.velSpring.update(entity.deltaMovement, stiffness, damping)
|
||||
return controller.velocity(entity, driver, input)
|
||||
}
|
||||
|
||||
@@ -134,6 +168,11 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
return controller.jumpForce(entity, driver, jumpStrength)
|
||||
}
|
||||
|
||||
fun getActiveRidingAltPose(entity: PokemonEntity, driver: Player): RidingAltPose {
|
||||
val controller = getController(entity) ?: return RidingAltPose.NONE
|
||||
return controller.getActiveRidingAltPose(entity, driver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to supply the delta for the lerp() between velocity
|
||||
* vectors. Called inertia for now as the way it feels when
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* Honestly having a base interface is probably unnecessary I'm just considering whether there's going to be some
|
||||
* kind of shared state later.
|
||||
@@ -15,4 +17,7 @@ package com.cobblemon.mod.common.api.riding
|
||||
* @author Hiroku
|
||||
* @since October 6th, 2024
|
||||
*/
|
||||
interface RidingState
|
||||
interface RidingState {
|
||||
var rideVel: Vec3
|
||||
var stamina: Float
|
||||
}
|
||||
+14
@@ -8,14 +8,18 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.controller
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.api.riding.RidingState
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.RidingAltPose
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -54,6 +58,14 @@ interface RideController : Encodable, Decodable {
|
||||
*/
|
||||
val condition: (PokemonEntity) -> Boolean
|
||||
|
||||
|
||||
/**
|
||||
* Returns the evaluation of the current stat when mapped to the given molang expression
|
||||
* that the controller implements. For composite controllers the active controller will
|
||||
* be determined rather than it evaluating its own expression.
|
||||
*/
|
||||
fun getStat(entity: PokemonEntity, stat: RidingStat): Double
|
||||
|
||||
/**
|
||||
* Specifies the pose the ridden mount should be positioned in. This queries the pose provider using
|
||||
* the entity as a means of determining the conditions the entity is currently under. This allows for
|
||||
@@ -111,6 +123,8 @@ interface RideController : Encodable, Decodable {
|
||||
|
||||
fun useAngVelSmoothing(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun getActiveRidingAltPose(entity: PokemonEntity, driver: Player): RidingAltPose = RidingAltPose.NONE
|
||||
|
||||
//If function is not overwritten by controllers then just perform the defualt
|
||||
//rolling function which is roll on mousex and pitch on mousey
|
||||
fun rotationOnMouseXY(
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.controller.posing
|
||||
|
||||
/**
|
||||
* The pose that will be used to determine if an alternate pose should be used while riding.
|
||||
*
|
||||
* @author Jackowes
|
||||
* @since March 23rd, 2025
|
||||
*/
|
||||
enum class RidingAltPose {
|
||||
NONE,
|
||||
GLIDING,
|
||||
SPRINTING,
|
||||
BRAKING,
|
||||
JUMPING;
|
||||
|
||||
companion object {
|
||||
fun fromString(name: String): RidingAltPose? {
|
||||
return entries.firstOrNull { it.name.equals(name, ignoreCase = true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.scale(20.0) // or Vec3.ZERO if you prefer
|
||||
}
|
||||
|
||||
val tick = min(lookBackTick, history.size - 2)
|
||||
val sprev = history.get(tick + 1).scale(20.0)
|
||||
val svalue = history.get(tick).scale(20.0)
|
||||
return sprev.add(svalue.subtract(sprev).scale(partialTick))
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
@@ -115,9 +116,10 @@ class ModelWidget(
|
||||
heldItemRenderer.renderOnModel(
|
||||
state.currentModel!!,
|
||||
heldItem?: ItemStack.EMPTY,
|
||||
state.locatorStates,
|
||||
state,
|
||||
matrices,
|
||||
context.bufferSource()
|
||||
context.bufferSource(),
|
||||
Vec3(0.0,-90.0,-90.0)
|
||||
)
|
||||
|
||||
matrices.popPose()
|
||||
|
||||
+88
-57
@@ -11,24 +11,24 @@ package com.cobblemon.mod.common.client.render.item
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags.WEARABLE_FACE_ITEMS
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags.WEARABLE_HAT_ITEMS
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.NullObjectParser
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.renderer.LightTexture
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.ItemDisplayContext
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class HeldItemRenderer() {
|
||||
private val itemRenderer = Minecraft.getInstance().itemRenderer
|
||||
private var displayContext = ItemDisplayContext.FIXED
|
||||
private var scale = 1.0f
|
||||
class HeldItemRenderer {
|
||||
private val itemRenderer: ItemRenderer = Minecraft.getInstance().itemRenderer
|
||||
private var displayContext: ItemDisplayContext = ItemDisplayContext.FIXED
|
||||
|
||||
companion object {
|
||||
const val ITEM_FACE = "item_face"
|
||||
@@ -37,99 +37,130 @@ class HeldItemRenderer() {
|
||||
}
|
||||
|
||||
fun render(
|
||||
entity: PokemonEntity?,
|
||||
entity: LivingEntity?,
|
||||
model: PosableModel,
|
||||
item: ItemStack,
|
||||
locators: Map<String, MatrixWrapper>,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int,
|
||||
seed: Int
|
||||
seed: Int,
|
||||
rotation: Vec3
|
||||
) {
|
||||
if (item.isEmpty) return
|
||||
displayContext = ItemDisplayContext.FIXED
|
||||
|
||||
poseStack.pushPose()
|
||||
when {
|
||||
//item_face locator
|
||||
(locators.containsKey(ITEM_FACE) && item.`is`(WEARABLE_FACE_ITEMS)) -> {
|
||||
displayContext = model.getLocatorDisplayContext(ITEM_FACE) ?: ItemDisplayContext.HEAD
|
||||
poseStack.mulPose(locators[ITEM_FACE]!!.matrix)
|
||||
poseStack.translate(0f, 0f, .28f * scale)
|
||||
poseStack.scale(0.7f * scale, 0.7f * scale, 0.7f * scale)
|
||||
poseStack.translate(0f, 0f, .28f)
|
||||
poseStack.scale(0.7f, 0.7f, 0.7f)
|
||||
}
|
||||
(locators.containsKey("item_hat") && item.`is`(WEARABLE_HAT_ITEMS)) -> {
|
||||
//item_hat locator
|
||||
(locators.containsKey(ITEM_HAT) && item.`is`(WEARABLE_HAT_ITEMS)) -> {
|
||||
displayContext = model.getLocatorDisplayContext(ITEM_HAT) ?: ItemDisplayContext.HEAD
|
||||
poseStack.mulPose(locators["item_hat"]!!.matrix)
|
||||
poseStack.translate(0f, -0.26f * scale, 0f)
|
||||
poseStack.scale(.68f * scale, .68f * scale, .68f * scale)
|
||||
poseStack.mulPose(locators[ITEM_HAT]!!.matrix)
|
||||
poseStack.translate(0f, -0.26f, 0f)
|
||||
poseStack.scale(.68f, .68f, .68f)
|
||||
}
|
||||
(locators.containsKey("item")) -> {
|
||||
updateModifiers("item",locators)
|
||||
poseStack.mulPose(locators["item"]!!.matrix)
|
||||
|
||||
//item locator
|
||||
(locators.containsKey(ITEM)) -> {
|
||||
displayContext = model.getLocatorDisplayContext(ITEM) ?: ItemDisplayContext.FIXED
|
||||
|
||||
when (displayContext) {
|
||||
ItemDisplayContext.FIXED -> {
|
||||
poseStack.translate(0f, 0.01666f * scale, 0f)
|
||||
poseStack.scale(.5f * scale, .5f * scale, .5f * scale)
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(90f))
|
||||
}
|
||||
ItemDisplayContext.THIRD_PERSON_RIGHT_HAND -> {
|
||||
poseStack.translate(0.075f* scale, 0f * scale, -0.05f* scale)
|
||||
poseStack.scale(scale, scale, scale)
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(-90f))
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(-90f))
|
||||
}
|
||||
else -> {
|
||||
poseStack.scale(scale, scale, scale)
|
||||
}
|
||||
}
|
||||
poseStack.mulPose(locators[ITEM]!!.matrix)
|
||||
applyContextTransformation(poseStack, rotation)
|
||||
}
|
||||
else -> { // Don't render any item
|
||||
// Don't render any item
|
||||
else -> {
|
||||
poseStack.popPose()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
itemRenderer.renderStatic(entity, item, displayContext, false, poseStack, buffer, null, light, OverlayTexture.NO_OVERLAY, seed)
|
||||
itemRenderer.renderStatic(entity, item, displayContext, (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND), poseStack, buffer, null, light, OverlayTexture.NO_OVERLAY, seed)
|
||||
poseStack.popPose()
|
||||
}
|
||||
|
||||
private fun renderAnimationItem(
|
||||
model: PosableModel,
|
||||
state: PosableState,
|
||||
locators: Map<String, MatrixWrapper>,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int,
|
||||
entity: LivingEntity?,
|
||||
rotation: Vec3
|
||||
) {
|
||||
state.itemRenderingLocations.forEach { (locatorName, item) ->
|
||||
poseStack.pushPose()
|
||||
if (locators.containsKey(locatorName)) {
|
||||
displayContext = model.getLocatorDisplayContext(locatorName)?: ItemDisplayContext.FIXED
|
||||
poseStack.mulPose(locators[locatorName]!!.matrix)
|
||||
applyContextTransformation(poseStack, rotation)
|
||||
}
|
||||
itemRenderer.renderStatic(entity, item, displayContext, (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND), poseStack, buffer, null, light, OverlayTexture.NO_OVERLAY, 0)
|
||||
poseStack.popPose()
|
||||
}
|
||||
}
|
||||
|
||||
fun renderOnModel(
|
||||
model: PosableModel,
|
||||
item: ItemStack,
|
||||
locators: Map<String, MatrixWrapper>,
|
||||
state: PosableState,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int = LightTexture.pack(11, 7)
|
||||
){
|
||||
if (!item.`is`(CobblemonItemTags.HIDDEN_ITEMS)) render(null, model, item, locators, poseStack, buffer, light, 0)
|
||||
rotation: Vec3 = Vec3(0.0,0.0,0.0),
|
||||
light: Int = LightTexture.pack(11, 7),
|
||||
) {
|
||||
val locators: Map<String, MatrixWrapper> = state.locatorStates
|
||||
if (state.itemRenderingLocations.isNotEmpty()) {
|
||||
renderAnimationItem(model, state, locators, poseStack, buffer, light, null, rotation)
|
||||
}
|
||||
else if (!item.`is`(CobblemonItemTags.HIDDEN_ITEMS)) {
|
||||
render(null, model, item, locators, poseStack, buffer, light, 0, rotation)
|
||||
}
|
||||
}
|
||||
|
||||
fun renderOnEntity(
|
||||
entity: PokemonEntity,
|
||||
delegate: PokemonClientDelegate,
|
||||
entity: LivingEntity,
|
||||
item: ItemStack,
|
||||
model: PosableModel,
|
||||
state: PosableState,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int
|
||||
light: Int,
|
||||
rotation: Vec3 = Vec3(0.0,0.0,0.0)
|
||||
) {
|
||||
val shownItem = entity.shownItem
|
||||
val locators: Map<String, MatrixWrapper> = delegate.locatorStates
|
||||
|
||||
render(entity, model, shownItem, locators, poseStack, buffer, light, 0)
|
||||
val locators: Map<String, MatrixWrapper> = state.locatorStates
|
||||
if (state.itemRenderingLocations.isNotEmpty()) {
|
||||
renderAnimationItem(model, state, locators, poseStack, buffer, light, entity, rotation)
|
||||
}
|
||||
else {
|
||||
render(entity, model, item, locators, poseStack, buffer, light, 0, rotation)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateModifiers(name: String, locators: Map<String, MatrixWrapper>) {
|
||||
locators.forEach { (locator: String, m: MatrixWrapper) ->
|
||||
val modifiers: Map<String, Float>
|
||||
if (locator.startsWith("_null_$name[")) {
|
||||
modifiers = NullObjectParser.parseNullObject(locator).modifiers
|
||||
if (modifiers.containsKey("scale")) scale = modifiers["scale"]!!
|
||||
if (modifiers.containsKey("mode")) displayContext = ItemDisplayContext.entries[((modifiers["mode"]!!).toInt()) % 9]
|
||||
return
|
||||
private fun applyContextTransformation(poseStack: PoseStack, rotation: Vec3) {
|
||||
when (displayContext) {
|
||||
ItemDisplayContext.FIXED -> {
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(90.0f))
|
||||
poseStack.scale(.5f, .5f, .5f )
|
||||
poseStack.translate(0f, 0.01666f, 0f)
|
||||
}
|
||||
ItemDisplayContext.THIRD_PERSON_RIGHT_HAND, ItemDisplayContext.THIRD_PERSON_LEFT_HAND -> {
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees((rotation.x).toFloat()))
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees((rotation.y).toFloat()))
|
||||
poseStack.mulPose(Axis.ZP.rotationDegrees((rotation.z).toFloat()))
|
||||
poseStack.translate(0.025f * if (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND) 1 else -1 , 0.0f, 0.0f)
|
||||
}
|
||||
ItemDisplayContext.HEAD -> {
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(90.0f))
|
||||
poseStack.scale(.6f, .6f, .6f)
|
||||
poseStack.translate(0f, -0.6f, 0f)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -37,6 +37,7 @@ import net.minecraft.nbt.Tag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PokemonOnShoulderRenderer<T : Player>(renderLayerParent: RenderLayerParent<T, PlayerModel<T>>) : RenderLayer<T, PlayerModel<T>>(renderLayerParent) {
|
||||
|
||||
@@ -163,9 +164,10 @@ class PokemonOnShoulderRenderer<T : Player>(renderLayerParent: RenderLayerParent
|
||||
heldItemRenderer.renderOnModel(
|
||||
model,
|
||||
shoulderData.shownItem,
|
||||
state.locatorStates,
|
||||
state,
|
||||
matrixStack,
|
||||
buffer
|
||||
buffer,
|
||||
Vec3(0.0,-90.0,-90.0)
|
||||
)
|
||||
|
||||
model.setDefault()
|
||||
|
||||
-50
@@ -1,50 +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
|
||||
|
||||
/**
|
||||
* Uses the name of null objects in a model to get modifier values for a locator.
|
||||
* @author Josh
|
||||
*/
|
||||
object NullObjectParser {
|
||||
fun parseNullObject(input: String): NullObjectModifier {
|
||||
// Extract modifiedLocator
|
||||
val modifiedLocator = input.replaceFirst("^_null_".toRegex(), "").replace("\\[.*\\]$".toRegex(), "")
|
||||
|
||||
// Extract modifiers
|
||||
val modifiers: MutableMap<String, Float> = HashMap()
|
||||
val start = input.indexOf('[')
|
||||
val end = input.indexOf(']')
|
||||
|
||||
if (start != -1 && end != -1 && end > start) {
|
||||
val modifierPart = input.substring(start + 1, end)
|
||||
val modifierPairs = modifierPart.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
|
||||
for (pair in modifierPairs) {
|
||||
val keyValue = pair.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (keyValue.size == 2) {
|
||||
val key = keyValue[0].trim { it <= ' ' }
|
||||
try {
|
||||
val value = keyValue[1].trim { it <= ' ' }.toFloat()
|
||||
modifiers[key] = value
|
||||
} catch (e: NumberFormatException) {
|
||||
System.err.println("Invalid number format for: " + keyValue[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NullObjectModifier(modifiedLocator, modifiers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores modifiers for a particular locator.
|
||||
*/
|
||||
class NullObjectModifier(val locatorName: String, val modifiers: Map<String, Float>)
|
||||
}
|
||||
+2
@@ -17,6 +17,7 @@ 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.animationFunctions
|
||||
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
|
||||
import com.cobblemon.mod.common.client.entity.NPCClientDelegate
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.AnimatedModelTextureSupplier
|
||||
import com.cobblemon.mod.common.client.render.ModelLayer
|
||||
@@ -56,6 +57,7 @@ import net.minecraft.client.renderer.texture.DynamicTexture
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.ItemDisplayContext
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix4f
|
||||
|
||||
+119
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
@@ -35,15 +36,20 @@ 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 net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.commands.arguments.item.ItemParser
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix4f
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
/**
|
||||
@@ -124,12 +130,107 @@ abstract class PosableState : Schedulable {
|
||||
/** This gets called 500 million times so use a mutable value for runtime */
|
||||
private val reusableAnimTime = DoubleValue(0.0)
|
||||
|
||||
val itemRenderingLocations = mutableMapOf<String, ItemStack>()
|
||||
// var itemRenderingLocation = ""
|
||||
// var animationItem : ItemStack? = null
|
||||
|
||||
/** All of the MoLang functions that can be applied to something with this state. */
|
||||
val functions = QueryStruct(hashMapOf())
|
||||
.addFunction("anim_time") {
|
||||
reusableAnimTime.value = animationSeconds.toDouble()
|
||||
reusableAnimTime
|
||||
}
|
||||
.addFunction("r_pitch") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickPitch = pokemon.riding.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
|
||||
val maxPitch = 90.0
|
||||
return@addFunction DoubleValue((partialTickPitch / maxPitch).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("r_yaw") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickYaw = pokemon.riding.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
|
||||
val maxYaw = 180.0
|
||||
return@addFunction DoubleValue((partialTickYaw / maxYaw).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("r_roll") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickRoll = pokemon.riding.rotSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
|
||||
val maxRoll = 180.0
|
||||
return@addFunction DoubleValue((partialTickRoll / maxRoll).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("r_yaw_change") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickYawDelt = pokemon.riding.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
|
||||
val maxRotRate = pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
|
||||
?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickYawDelt / maxRotRate).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("r_pitch_change") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickPitchDelt = pokemon.riding.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
|
||||
val maxRotRate = pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
|
||||
?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickPitchDelt / maxRotRate).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction(" r_roll_change") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
val partialTickRollDelt = pokemon.riding.rotDeltaSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
|
||||
val maxRotRate = pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SKILL)
|
||||
?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickRollDelt / maxRotRate).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("r_speed") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickSpeed = pokemon.riding.velSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).length()
|
||||
val topSpeed = pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
return@addFunction DoubleValue((partialTickSpeed / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("r_speed_x") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickXVel = pokemon.riding.velSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
|
||||
|
||||
val topSpeed = pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickXVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("r_speed_y") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickYVel = pokemon.riding.velSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
|
||||
|
||||
val topSpeed = pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickYVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("r_speed_z") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickZVel = pokemon.riding.velSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
|
||||
|
||||
val topSpeed = pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("current_aspects") { ArrayStruct(currentAspects.mapIndexed { index, s -> "$index" to StringValue(s)}.toMap())}
|
||||
.addFunction("has_aspect") { params -> DoubleValue(params.get<MoValue>(0).asString() in currentAspects) }
|
||||
.addFunction("has_entity") { DoubleValue(getEntity() != null) }
|
||||
@@ -148,6 +249,24 @@ abstract class PosableState : Schedulable {
|
||||
)
|
||||
}
|
||||
}
|
||||
.addFunction("render_item") { params ->
|
||||
if (params.get<MoValue>(0) !is StringValue) return@addFunction Unit
|
||||
|
||||
val client = Minecraft.getInstance().connection ?: return@addFunction Unit
|
||||
val result = ItemParser(client.registryAccess()).parse(StringReader(params.getString(0)))
|
||||
val item = ItemStack(result.item)
|
||||
item.applyComponents(result.components)
|
||||
|
||||
val renderLocation = if (params.contains(1)) params.getString(1) else "item"
|
||||
|
||||
if (!item.isEmpty && locatorStates.containsKey(renderLocation)) {
|
||||
itemRenderingLocations.put(renderLocation, item)
|
||||
} else {
|
||||
if (itemRenderingLocations.containsKey(renderLocation)) itemRenderingLocations.remove(renderLocation)
|
||||
return@addFunction Unit
|
||||
}
|
||||
}
|
||||
.addFunction("clear_items") { itemRenderingLocations.clear() }
|
||||
.addFunction("play_animation") { params ->
|
||||
val animationParameter = params.get<MoValue>(0)
|
||||
val animation = if (animationParameter is ObjectValue<*>) {
|
||||
|
||||
-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
|
||||
}
|
||||
-1
@@ -497,7 +497,6 @@ object VaryingModelRepository {
|
||||
inbuilt("taillow", ::TaillowModel)
|
||||
inbuilt("swellow", ::SwellowModel)
|
||||
inbuilt("mudbray", ::MudbrayModel)
|
||||
inbuilt("mudsdale", ::MudsdaleModel)
|
||||
inbuilt("comfey", ::ComfeyModel)
|
||||
inbuilt("tandemaus", ::TandemausModel)
|
||||
inbuilt("maushold", ::MausholdModel)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.render.npc
|
||||
|
||||
import com.cobblemon.mod.common.client.entity.NPCClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.item.HeldItemRenderer
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableEntityModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.npc.PosableNPCModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
|
||||
@@ -19,6 +20,7 @@ import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider.Context
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.min
|
||||
|
||||
class NPCRenderer(context: Context) : LivingEntityRenderer<NPCEntity, PosableEntityModel<NPCEntity>>(context, PosableNPCModel(), 0.5f) {
|
||||
@@ -26,6 +28,8 @@ class NPCRenderer(context: Context) : LivingEntityRenderer<NPCEntity, PosableEnt
|
||||
return VaryingModelRepository.getTexture(entity.npc.resourceIdentifier, (entity.delegate as NPCClientDelegate))
|
||||
}
|
||||
|
||||
private val heldItemRenderer = HeldItemRenderer()
|
||||
|
||||
override fun render(
|
||||
entity: NPCEntity,
|
||||
entityYaw: Float,
|
||||
@@ -56,6 +60,20 @@ class NPCRenderer(context: Context) : LivingEntityRenderer<NPCEntity, PosableEnt
|
||||
model.blue = 1F
|
||||
model.resetLayerContext()
|
||||
|
||||
if (entity.deathTime < 1){
|
||||
//Render Held Item
|
||||
heldItemRenderer.renderOnEntity(
|
||||
entity,
|
||||
entity.mainHandItem,
|
||||
model,
|
||||
clientDelegate,
|
||||
poseMatrix,
|
||||
buffer,
|
||||
packedLight,
|
||||
Vec3(-90.0,0.0,0.0)
|
||||
)
|
||||
}
|
||||
|
||||
// if (this.shouldRenderLabel(entity)) {
|
||||
// this.renderLabelIfPresent(entity, entity.displayName, poseMatrix, buffer, packedLight)
|
||||
// }
|
||||
|
||||
+5
-3
@@ -101,7 +101,7 @@ class PokemonRenderer(
|
||||
packedLight: Int
|
||||
) {
|
||||
val clientDelegate = entity.delegate as PokemonClientDelegate
|
||||
shadowRadius = min((entity.boundingBox.maxX - entity.boundingBox.minX), (entity.boundingBox.maxZ) - (entity.boundingBox.minZ)).toFloat() / 1.5F * (entity.delegate as PokemonClientDelegate).entityScaleModifier
|
||||
shadowRadius = (min((entity.boundingBox.maxX - entity.boundingBox.minX), (entity.boundingBox.maxZ) - (entity.boundingBox.minZ)).toFloat() / 1.5F * (entity.delegate as PokemonClientDelegate).entityScaleModifier)/entity.scale
|
||||
model.posableModel = VaryingModelRepository.getPoser(entity.pokemon.species.resourceIdentifier, clientDelegate)
|
||||
model.posableModel.context = model.context
|
||||
model.setupEntityTypeContext(entity)
|
||||
@@ -160,11 +160,13 @@ class PokemonRenderer(
|
||||
//Render Held Item
|
||||
heldItemRenderer.renderOnEntity(
|
||||
entity,
|
||||
clientDelegate,
|
||||
entity.shownItem,
|
||||
model.posableModel,
|
||||
clientDelegate,
|
||||
poseMatrix,
|
||||
buffer,
|
||||
packedLight
|
||||
packedLight,
|
||||
Vec3(0.0,-90.0,90.0)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -557,10 +557,10 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
|
||||
private fun pokemonExpressions(pokemon: Pokemon): List<String> {
|
||||
return listOf(
|
||||
"v.actioning_pokemon_name=\"${pokemon.species.name}\";",
|
||||
"v.actioning_pokemon_name=\'${pokemon.species.name}\';",
|
||||
"v.actioning_pokemon_level=${pokemon.level};",
|
||||
"v.actioning_pokemon_ball=\"${pokemon.caughtBall.name}\";",
|
||||
"v.actioning_pokemon_shiny=\"${pokemon.shiny}\";",
|
||||
"v.actioning_pokemon_ball=\'${pokemon.caughtBall.name}\';",
|
||||
"v.actioning_pokemon_shiny=\'${pokemon.shiny}\';",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.entity.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.*
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.drop.DropTable
|
||||
import com.cobblemon.mod.common.api.entity.Despawner
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSender
|
||||
@@ -38,6 +36,7 @@ import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.riding.*
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.RidingAltPose
|
||||
import com.cobblemon.mod.common.api.riding.events.SelectDriverEvent
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
@@ -86,11 +85,6 @@ import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import com.mojang.serialization.Codec
|
||||
import java.util.EnumSet
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.PI
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
@@ -143,6 +137,9 @@ import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Vector3f
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.PI
|
||||
|
||||
@Suppress("unused")
|
||||
open class PokemonEntity(
|
||||
@@ -959,6 +956,7 @@ open class PokemonEntity(
|
||||
val scale = effects.mockEffect?.scale ?: (form.baseScale * pokemon.scaleModifier)
|
||||
var result = this.exposedForm.hitbox.scale(scale)
|
||||
result = result.withEyeHeight(this.exposedForm.eyeHeight(this) * result.height)
|
||||
result = result.scale(this.scale)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1310,7 +1308,7 @@ open class PokemonEntity(
|
||||
}
|
||||
} else if (form.behaviour.moving.swim.canBreatheUnderwater && !form.behaviour.moving.swim.canWalkOnWater) {
|
||||
// Use half hitbox height for swimmers
|
||||
val halfHeight = form.hitbox.height * form.baseScale / 2.0
|
||||
val halfHeight = getDimensions(this.pose).height / 2.0
|
||||
for (i in 1..halfHeight.toInt()) {
|
||||
blockPos = blockPos.below()
|
||||
if (!this.level().isWaterAt(blockPos) || !this.level().getBlockState(blockPos).getCollisionShape(this.level(), blockPos).isEmpty) {
|
||||
@@ -1409,11 +1407,22 @@ open class PokemonEntity(
|
||||
if (riders.isEmpty()) {
|
||||
super.handleRelativeFrictionAndCalculateMovement(deltaMovement, friction)
|
||||
} else {
|
||||
//val scale =
|
||||
//Handle ridden pokemon differently to allow vector lerp instead of simple addition.
|
||||
val v = Entity.getInputVector(riding.velocity(this, this.controllingPassenger as Player, Vec3.ZERO), 1.0f, this.getYRot());
|
||||
//val v = Entity.getInputVector(riding.velocity(this, this.controllingPassenger as Player, Vec3.ZERO), 1.0f, this.getYRot());
|
||||
val v = Entity.getInputVector(riding.velocity(this, this.controllingPassenger as Player, Vec3.ZERO), 1.0f, this.getYRot()).scale(this.speed.toDouble())
|
||||
//changing this will give the ride more or less inertia/handling/drift
|
||||
this.deltaMovement = this.deltaMovement.lerp(v, riding.inertia(this));
|
||||
this.move(MoverType.SELF, this.deltaMovement.scale(this.speed.toDouble()))
|
||||
|
||||
//val smoothingFactor = 0.5
|
||||
//val t = 1.0 - exp(-smoothingFactor)
|
||||
|
||||
val diff = v.subtract(this.deltaMovement)
|
||||
|
||||
this.deltaMovement = this.deltaMovement.add( diff.scale(0.1) )
|
||||
|
||||
//this.deltaMovement = this.deltaMovement.lerp(v, riding.inertia(this))
|
||||
//this.deltaMovement = this.deltaMovement.scale(this.speed.toDouble()).lerp(v, riding.inertia(this));
|
||||
this.move(MoverType.SELF, this.deltaMovement)
|
||||
}
|
||||
|
||||
return this.deltaMovement
|
||||
@@ -1435,14 +1444,36 @@ open class PokemonEntity(
|
||||
if (beamMode != 3) { // Don't let Pokémon move during recall
|
||||
|
||||
//Prevent current travel logic when riding a pokemon.
|
||||
/*
|
||||
val riders = this.passengers.filterIsInstance<LivingEntity>()
|
||||
if ( riders.isEmpty() ) {
|
||||
super.travel(movementInput)
|
||||
}
|
||||
*/
|
||||
else {
|
||||
//val v = Entity.getInputVector(riding.velocity(this, this.controllingPassenger as Player, Vec3.ZERO), this.speed.toFloat(), this.getYRot())
|
||||
val inp = riding.velocity(this, this.controllingPassenger as Player, Vec3.ZERO)
|
||||
|
||||
val f = Mth.sin(this.getYRot() * 0.017453292f)
|
||||
val g = Mth.cos(this.getYRot() * 0.017453292f)
|
||||
val v = Vec3(
|
||||
inp.x * g.toDouble() - inp.z * f.toDouble(),
|
||||
inp.y,
|
||||
inp.z * g.toDouble() + inp.x * f.toDouble()
|
||||
)
|
||||
|
||||
//val smoothingFactor = 0.5
|
||||
//val t = 1.0 - exp(-smoothingFactor)
|
||||
|
||||
val diff = v.subtract(this.deltaMovement)
|
||||
|
||||
this.deltaMovement = this.deltaMovement.add( diff.scale(riding.inertia(this)) )
|
||||
|
||||
//this.deltaMovement = this.deltaMovement.lerp(v, riding.inertia(this))
|
||||
//this.deltaMovement = this.deltaMovement.scale(this.speed.toDouble()).lerp(v, riding.inertia(this));
|
||||
this.move(MoverType.SELF, this.deltaMovement)
|
||||
}
|
||||
|
||||
|
||||
|
||||
super.travel(movementInput)
|
||||
|
||||
this.updateBlocksTraveled(prevBlockPos)
|
||||
}
|
||||
@@ -1812,6 +1843,11 @@ open class PokemonEntity(
|
||||
return this.riding.speed(this, controller)
|
||||
}
|
||||
|
||||
fun getActiveRidingAltPose(): RidingAltPose {
|
||||
val driver = this.controllingPassenger as? Player ?: return RidingAltPose.NONE
|
||||
return this.riding.getActiveRidingAltPose(this, driver)
|
||||
}
|
||||
|
||||
var jumpInputStrength: Int = 0 // move this
|
||||
override fun onPlayerJump(strength: Int) {
|
||||
// See if this controls the hot bar element
|
||||
|
||||
+241
-117
@@ -9,16 +9,19 @@
|
||||
package com.cobblemon.mod.common.pokemon.riding.controllers
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.RidingAltPose
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.BirdAirState
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -32,81 +35,37 @@ class BirdAirController : RideController {
|
||||
override val poseProvider = PoseProvider(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) {
|
||||
val player = it.passengers.firstOrNull() as? Player ?: return@PoseOption false
|
||||
it.deltaMovement.length() > 0.3 })
|
||||
/*
|
||||
.with(PoseOption(PoseType.FLY) {
|
||||
val player = it.passengers.firstOrNull() as? Player ?: return@PoseOption false
|
||||
player.zza > 0.0f // Checks if the player is actively attempting to move forward
|
||||
})
|
||||
*/
|
||||
it.deltaMovement.length() > 0.5 })
|
||||
|
||||
override val condition: (PokemonEntity) -> Boolean = { true }
|
||||
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression(),
|
||||
// Max accel is a whole 1.0 in 3 seconds. The conversion in the function below is to convert seconds to ticks
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression(),
|
||||
//Seconds self propelled flight (glide is not self propelled in this case)
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression(),
|
||||
//max y level for the ride
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
)
|
||||
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
var horizontalAcceleration: Expression = "0.1".asExpression()
|
||||
private set
|
||||
var verticalAcceleration: Expression = "0.1".asExpression()
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
// Where 90 is the width of the range and 45 is the offset.
|
||||
// So the handling interpolates between 135 and 45
|
||||
var handlingExpr: Expression = "(q.get_ride_stats('SKILL', 'AIR') / 100) * 90 + 45".asExpression()
|
||||
private set
|
||||
var topSpeedExpr: Expression = "(q.get_ride_stats('SPEED', 'AIR') / 100) * (1.0 - 0.35) + 0.35".asExpression()
|
||||
private set
|
||||
//Reaches max top speed from a standstill at minimum 8 seconds and max 3 seconds.
|
||||
//This is a bit of a confusing expression and likely should be cleaned up to be more readable
|
||||
var accelExpr: Expression = "(q.get_ride_stats('ACCELERATION', 'AIR') / 100) * (0.01666666666 - 0.00625) + 0.00625".asExpression()
|
||||
private set
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
|
||||
//Retrieve the current bird controller state
|
||||
//val state = entity.riding.getState(KEY) { e -> BirdAirControllerState(e) }
|
||||
//Retrieve the current bird controller state and stats
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
//retrieve stats
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val accel = getRuntime(entity).resolveDouble(accelExpr)
|
||||
|
||||
val maxGlideSpeed = topSpeed * 2
|
||||
var glideSpeedChange = 0.00
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza > 0.0 && state.currSpeed < topSpeed) {
|
||||
state.currSpeed = min(state.currSpeed + accel , topSpeed)
|
||||
} else if (driver.zza < 0.0 && state.currSpeed > 0.0) {
|
||||
//Decelerate is currently always a constant half of max acceleration.
|
||||
state.currSpeed = max(state.currSpeed - (0.0166 / 2), 0.0)
|
||||
}
|
||||
|
||||
val rollable = driver as? Rollable
|
||||
if (rollable != null) {
|
||||
glideSpeedChange = sin(Math.toRadians(rollable.pitch.toDouble()))
|
||||
glideSpeedChange = glideSpeedChange.pow(3)
|
||||
|
||||
//TODO: Possibly create a deadzone around parallel where speed isn't taken away from?
|
||||
if (glideSpeedChange <= 0.0) {
|
||||
//Ensures that a propelling force is still able to be applied when
|
||||
//climbing in height
|
||||
if (driver.zza <= 0) {
|
||||
//speed decrease should be 2x speed increase?
|
||||
state.currSpeed = max(state.currSpeed + (0.0166) * glideSpeedChange, 0.0 )
|
||||
}
|
||||
} else {
|
||||
// only add to the speed if it hasn't exceeded the current
|
||||
//glide angles maximum amount of speed that it can give.
|
||||
state.currSpeed = min(state.currSpeed + ((0.0166 * 2) * glideSpeedChange), maxGlideSpeed)
|
||||
}
|
||||
}
|
||||
|
||||
//air resistance
|
||||
state.currSpeed = max(state.currSpeed - 0.005, 0.0)
|
||||
|
||||
return state.currSpeed.toFloat()
|
||||
return state.rideVel.length().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
@@ -118,62 +77,60 @@ class BirdAirController : RideController {
|
||||
var leftForce = 0.0
|
||||
var upForce = 0.0
|
||||
var forwardForce = 0.0
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
//Perform ride velocity update
|
||||
calculateRideSpaceVel(entity, driver, state)
|
||||
|
||||
//Translate ride space velocity to world space velocity.
|
||||
val rollable = driver as? Rollable
|
||||
if (rollable != null) {
|
||||
//Need to deadzone this when straight up or down
|
||||
// test with and without strafing added. May be wanted while moving
|
||||
leftForce = -1.0 * sin(Math.toRadians(rollable.roll.toDouble()))
|
||||
|
||||
upForce = -1.0 * sin(Math.toRadians(rollable.pitch.toDouble()))
|
||||
upForce += -1.0 * sin(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.z
|
||||
forwardForce += cos(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.z
|
||||
|
||||
forwardForce = cos(Math.toRadians(rollable.pitch.toDouble()))
|
||||
upForce += cos(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.y
|
||||
forwardForce += sin(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.y
|
||||
}
|
||||
|
||||
//TODO: Add in an upwards and downwards force when pressing space maybe?
|
||||
|
||||
//Leave out tap to flap right now
|
||||
/*
|
||||
var jumpVector = Vec3.ZERO
|
||||
if (entity.jumpInputStrength > 0) {
|
||||
val runtime = getRuntime(entity)
|
||||
runtime.environment.query.addFunction("jump_strength") { DoubleValue(entity.jumpInputStrength.toDouble()) }
|
||||
val jumpForces = this.jumpVector.map { runtime.resolveFloat(it) }
|
||||
jumpVector = Vec3(jumpForces[0].toDouble(), jumpForces[1].toDouble(), jumpForces[2].toDouble())
|
||||
jumpVector = jumpVector.toVector3f().mul((driver as Rollable).orientation).toVec3d()
|
||||
entity.jumpInputStrength = 0
|
||||
entity.addDeltaMovement(jumpVector)
|
||||
//Bring the ride out of the sky when stamina is depleted.
|
||||
if (state.stamina <= 0.0) {
|
||||
upForce -= 0.3
|
||||
}
|
||||
*/
|
||||
//Retrieve the current composite controller state
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
val velocity = Vec3(0.0 , upForce * state.currSpeed, forwardForce * state.currSpeed)
|
||||
val altitudeLimit = this.getStat(entity, RidingStat.JUMP)
|
||||
|
||||
//Only limit altitude if altitude is not infinite
|
||||
if (!getRuntime(entity).resolveBoolean(infiniteAltitude)) {
|
||||
//Provide a hard limit on altitude
|
||||
upForce = if (entity.y >= altitudeLimit && upForce > 0) 0.0 else upForce
|
||||
}
|
||||
|
||||
val velocity = Vec3(state.rideVel.x , upForce, forwardForce)
|
||||
return velocity
|
||||
}
|
||||
|
||||
override fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
|
||||
val rollable = driver as? Rollable
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
//TODO: Tie in handling
|
||||
val handling = getRuntime(entity).resolveDouble(handlingExpr)
|
||||
val handling = this.getStat(entity, RidingStat.SKILL)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val rotationChangeRate = 10.0
|
||||
|
||||
if (rollable != null) {
|
||||
var yawForce = rotationChangeRate * sin(Math.toRadians(rollable.roll.toDouble()))
|
||||
//for a bit of correction on the rolls limit it to a quarter the amount
|
||||
var pitchForce = -0.25 * rotationChangeRate * abs(sin(Math.toRadians(rollable.roll.toDouble())))
|
||||
var pitchForce = -0.35 * rotationChangeRate * abs(sin(Math.toRadians(rollable.roll.toDouble())))
|
||||
|
||||
//limit rotation modulation when pitched up heavily or pitched down heavily
|
||||
yawForce *= abs(cos(Math.toRadians(rollable.pitch.toDouble())))
|
||||
pitchForce *= abs(cos(Math.toRadians(rollable.pitch.toDouble()))) * 1.5
|
||||
|
||||
//Create a deadzone for easier leveling out
|
||||
if (rollable.roll <= 0.0 && rollable.roll >= -0.0) {
|
||||
yawForce = 0.0
|
||||
pitchForce = 0.0
|
||||
}
|
||||
return Vec3(yawForce, pitchForce, 0.0)
|
||||
}
|
||||
|
||||
@@ -191,42 +148,56 @@ class BirdAirController : RideController {
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is Rollable) return Vec3.ZERO
|
||||
|
||||
val rollable = driver as Rollable
|
||||
|
||||
val handling = getRuntime(entity).resolveDouble(handlingExpr)
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
val handling = this.getStat(entity, RidingStat.SKILL)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
var xInput = xMouseSmoother.getNewDeltaValue(xMouse * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
val YInput = yMouseSmoother.getNewDeltaValue(yMouse * 0.1 * invertPitch, deltaTime * smoothingSpeed);
|
||||
val xInput = xMouseSmoother.getNewDeltaValue(xMouse * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
val yInput = yMouseSmoother.getNewDeltaValue(yMouse * 0.1 * invertPitch, deltaTime * smoothingSpeed);
|
||||
|
||||
//limit rolling based on healing
|
||||
val rotLimit = 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
|
||||
val rotMin = 15.0
|
||||
var rollForce = xInput
|
||||
val rotLimit = max(handling * normalizeVal(state.rideVel.length(), 0.0, topSpeed).pow(3), rotMin)
|
||||
|
||||
//Limit roll by non linearly decreasing inputs towards
|
||||
// a rotation limit based on the current distance from
|
||||
// that rotation limit
|
||||
if (abs(rollable.roll + xInput) < rotLimit) {
|
||||
if (sign(xInput) == sign(rollable.roll).toDouble()) {
|
||||
if (abs(rollable.roll + rollForce) < rotLimit) {
|
||||
if (sign(rollForce) == sign(rollable.roll).toDouble()) {
|
||||
val d = abs(abs(rollable.roll) - rotLimit)
|
||||
xInput *= (d.pow(2)) / (rotLimit.pow(2))
|
||||
rollForce *= (d.pow(2)) / (rotLimit.pow(2))
|
||||
}
|
||||
} else if (sign(xInput) == sign(rollable.roll).toDouble()) {
|
||||
xInput = 0.0
|
||||
} else if (sign(rollForce) == sign(rollable.roll).toDouble()) {
|
||||
rollForce = 0.0
|
||||
}
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * ( 1.0 - normalizeVal(state.rideVel.length(), 0.0, topSpeed).pow(3))
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, YInput, xInput)
|
||||
return Vec3(yawForce, yInput, rollForce)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(entity: PokemonEntity, driver: Player): Float {
|
||||
//Retrieve stamina from state
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
return (state.stamina / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
@@ -243,29 +214,182 @@ class BirdAirController : RideController {
|
||||
|
||||
override fun shouldRoll(entity: PokemonEntity) = true
|
||||
|
||||
override fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val glideTopSpeed = topSpeed * 1.5 //TODO: Should this be refined?
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
//Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedGlideSpeed = normalizeVal(state.rideVel.length(), topSpeed, glideTopSpeed)
|
||||
|
||||
//Only ever want the fov change to be a max of 0.2 and for it to have non linear scaling.
|
||||
return 1.0f + normalizedGlideSpeed.pow(2).toFloat() * 0.2f
|
||||
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(entity: PokemonEntity): Boolean = false
|
||||
|
||||
override fun getActiveRidingAltPose(entity: PokemonEntity, driver: Player): RidingAltPose {
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
val pose = if (state.gliding) RidingAltPose.GLIDING else RidingAltPose.NONE
|
||||
return pose
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeString(gravity.toString())
|
||||
buffer.writeString(horizontalAcceleration.toString())
|
||||
buffer.writeString(verticalAcceleration.toString())
|
||||
buffer.writeString(topSpeedExpr.toString())
|
||||
buffer.writeString(accelExpr.toString())
|
||||
buffer.writeString(handlingExpr.toString())
|
||||
buffer.writeString(infiniteStamina.toString())
|
||||
buffer.writeString(infiniteAltitude.toString())
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
gravity = buffer.readString().asExpression()
|
||||
horizontalAcceleration = buffer.readString().asExpression()
|
||||
verticalAcceleration = buffer.readString().asExpression()
|
||||
topSpeedExpr = buffer.readString().asExpression()
|
||||
accelExpr = buffer.readString().asExpression()
|
||||
handlingExpr = buffer.readString().asExpression()
|
||||
infiniteStamina = buffer.readString().asExpression()
|
||||
infiniteAltitude = buffer.readString().asExpression()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/bird")
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalizes the given value between a min and a max.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents x is at or below min
|
||||
* and 1.0 represents x is at or above it.
|
||||
*/
|
||||
fun normalizeVal(x: Double, min: Double, max: Double): Double {
|
||||
require(max > min) { "max must be greater than min" }
|
||||
return ((x - min) / (max - min)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the change in the ride space vector due to player input and ride state
|
||||
*/
|
||||
fun calculateRideSpaceVel(entity: PokemonEntity, driver: Player, state: BirdAirState) {
|
||||
|
||||
|
||||
//retrieve stats
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val glideTopSpeed = topSpeed * 1.5
|
||||
val accel = this.getStat(entity, RidingStat.ACCELERATION)
|
||||
val staminaStat = this.getStat(entity, RidingStat.STAMINA)
|
||||
|
||||
var glideSpeedChange = 0.00
|
||||
|
||||
val currSpeed = state.rideVel.length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina > 0.0) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
driver.zza > 0 && state.rideVel.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && state.rideVel.z < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
(state.rideVel.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
val rollable = driver as? Rollable
|
||||
if (rollable != null) {
|
||||
//Base glide speed change on current pitch of the ride.
|
||||
glideSpeedChange = sin(Math.toRadians(rollable.pitch.toDouble()))
|
||||
glideSpeedChange = glideSpeedChange.pow(3) * 0.5
|
||||
|
||||
//TODO: Possibly create a deadzone around parallel where glide doesn't affect speed?
|
||||
if (glideSpeedChange <= 0.0) {
|
||||
//Ensures that a propelling force is still able to be applied when
|
||||
//climbing in height
|
||||
if (driver.zza <= 0) {
|
||||
//speed decrease should be 2x speed increase?
|
||||
//state.currSpeed = max(state.currSpeed + (0.0166) * glideSpeedChange, 0.0 )
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
lerp( state.rideVel.z, 0.0,glideSpeedChange * -0.0166 * 2 ))
|
||||
}
|
||||
} else {
|
||||
// only add to the speed if it hasn't exceeded the current
|
||||
//glide angles maximum amount of speed that it can give.
|
||||
//state.currSpeed = min(state.currSpeed + ((0.0166 * 2) * glideSpeedChange), maxGlideSpeed)
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
min(state.rideVel.z + ((0.0166 * 2) * glideSpeedChange), glideTopSpeed))
|
||||
}
|
||||
}
|
||||
|
||||
//Lateral movement based on driver input.
|
||||
val latTopSpeed = topSpeed / 2.0
|
||||
if (driver.xxa != 0.0f && state.stamina > 0.0) {
|
||||
state.rideVel = Vec3(
|
||||
(state.rideVel.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
|
||||
state.rideVel.y,
|
||||
state.rideVel.z)
|
||||
activeInput = true
|
||||
}
|
||||
else {
|
||||
state.rideVel = Vec3(
|
||||
lerp(state.rideVel.x, 0.0, latTopSpeed / 20.0),
|
||||
state.rideVel.y,
|
||||
state.rideVel.z)
|
||||
}
|
||||
|
||||
//Vertical movement based on driver input.
|
||||
val vertTopSpeed = topSpeed / 2.0
|
||||
val vertInput = when {
|
||||
Minecraft.getInstance().options.keyJump.isDown() -> 1.0
|
||||
Minecraft.getInstance().options.keyShift.isDown() -> -1.0
|
||||
else -> 0.0
|
||||
}
|
||||
|
||||
if (vertInput != 0.0 && state.stamina > 0.0) {
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
(state.rideVel.y + (accel * vertInput)).coerceIn(-vertTopSpeed, vertTopSpeed),
|
||||
state.rideVel.z)
|
||||
activeInput = true
|
||||
}
|
||||
else {
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
lerp(state.rideVel.y, 0.0, vertTopSpeed / 20.0),
|
||||
state.rideVel.z)
|
||||
}
|
||||
|
||||
//Check if the ride should be gliding
|
||||
if (activeInput && state.stamina > 0.0) {
|
||||
state.gliding = false
|
||||
}else {
|
||||
state.gliding = true
|
||||
}
|
||||
|
||||
//Only perform stamina logic if the ride does not have infinite stamina
|
||||
if (!getRuntime(entity).resolveBoolean(infiniteStamina)) {
|
||||
if (activeInput) {
|
||||
state.stamina -= (0.05 / staminaStat).toFloat()
|
||||
}
|
||||
|
||||
//Lose a base amount of stamina just for being airborne
|
||||
state.stamina -= (0.01 / staminaStat).toFloat()
|
||||
}
|
||||
else
|
||||
{
|
||||
state.stamina = 1.0f
|
||||
}
|
||||
|
||||
//air resistance
|
||||
//TODO: This method is very unrefined and will need to be an active point of testing
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
lerp( state.rideVel.z,0.0, topSpeed / ( 20.0 * 30.0)))
|
||||
}
|
||||
}
|
||||
+295
-114
@@ -8,53 +8,37 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.riding.controllers
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.DolphinLiquidState
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth.lerp
|
||||
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.abs
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.math.*
|
||||
|
||||
class DolphinController : RideController {
|
||||
companion object {
|
||||
val KEY: ResourceLocation = cobblemonResource("swim/dolphin")
|
||||
}
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
var speed = "1.0".asExpression()
|
||||
private set
|
||||
var driveFactor = "1.0".asExpression()
|
||||
private set
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
var lastVelocity = Vec3(0.0,0.0,0.0)
|
||||
private set
|
||||
|
||||
private val rollSmoother = SmoothDouble()
|
||||
|
||||
override val key: ResourceLocation = KEY
|
||||
override val poseProvider: PoseProvider = PoseProvider(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { it.deltaMovement.length() >= 0.05 })
|
||||
/*
|
||||
override val condition: (PokemonEntity) -> Boolean = { entity ->
|
||||
|
||||
//If there are only fluid blocks or air block below the ride
|
||||
@@ -68,135 +52,332 @@ class DolphinController : RideController {
|
||||
true
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
override val condition: (PokemonEntity) -> Boolean = { true }
|
||||
|
||||
//TODO:Implement real values for this
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'LIQUID', 135.0, 45.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'LIQUID', 0.6, 0.2)".asExpression(),
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'LIQUID', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression(),
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'LIQUID', 120.0, 20.0)".asExpression(),
|
||||
//max y level for the ride
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'LIQUID', 200.0, 128.0)".asExpression()
|
||||
)
|
||||
|
||||
var glideTopSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'LIQUID', 2.0, 1.0)".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
return getRuntime(entity).resolveFloat(speed)
|
||||
|
||||
//Retrieve the current bird controller state and stats
|
||||
val state = getState(entity, ::DolphinLiquidState)
|
||||
|
||||
return state.rideVel.length().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot )
|
||||
}
|
||||
|
||||
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun inertia(entity: PokemonEntity ): Double
|
||||
{
|
||||
return 0.05
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
|
||||
val runtime = getRuntime(entity)
|
||||
var yVel = 0.0
|
||||
var leftForce = 0.0
|
||||
var upForce = 0.0
|
||||
var forwardForce = 0.0
|
||||
val state = getState(entity, ::DolphinLiquidState)
|
||||
|
||||
if (!entity.isInWater && !entity.isUnderWater)
|
||||
{
|
||||
lastVelocity = Vec3(lastVelocity.x, lastVelocity.y - 0.035, lastVelocity.z)
|
||||
return lastVelocity
|
||||
}
|
||||
//Perform ride velocity update
|
||||
calculateRideSpaceVel(entity, driver, state)
|
||||
|
||||
val driveFactor = runtime.resolveFloat(this.driveFactor)
|
||||
val strafeFactor = runtime.resolveFloat(this.strafeFactor)
|
||||
val f = driver.xxa * strafeFactor
|
||||
var g = driver.zza * driveFactor
|
||||
if (g <= 0.0f) {
|
||||
g *= runtime.resolveFloat(this.reverseDriveFactor)
|
||||
}
|
||||
|
||||
var yComp = 0.0
|
||||
|
||||
//Get roll to add a left and right strafe during roll
|
||||
//Not sure if this is desired? Will need to mess around with this
|
||||
//a bit more
|
||||
var zComp = 0.0
|
||||
//Translate ride space velocity to world space velocity.
|
||||
val rollable = driver as? Rollable
|
||||
if (rollable != null)
|
||||
{
|
||||
//Can be used again if I better figure out how to deadzone it near the tops?
|
||||
zComp = -1.0 * g.toDouble() * sin(Math.toRadians(rollable.roll.toDouble()))
|
||||
yComp = -1.0 * g.toDouble() * sin(Math.toRadians(rollable.pitch.toDouble()))
|
||||
if (rollable != null) {
|
||||
//Need to deadzone this when straight up or down
|
||||
|
||||
upForce += -1.0 * sin(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.z
|
||||
forwardForce += cos(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.z
|
||||
|
||||
upForce += cos(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.y
|
||||
forwardForce += sin(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.y
|
||||
}
|
||||
|
||||
val currVelocity = Vec3(0.0, yComp , g.toDouble())
|
||||
lastVelocity = currVelocity
|
||||
return currVelocity
|
||||
|
||||
//Bring the ride out of the sky when stamina is depleted.
|
||||
if (state.stamina <= 0.0) {
|
||||
upForce -= 0.3
|
||||
}
|
||||
|
||||
val altitudeLimit = this.getStat(entity, RidingStat.JUMP)
|
||||
|
||||
//Only limit altitude if altitude is not infinite
|
||||
if (!getRuntime(entity).resolveBoolean(infiniteAltitude)) {
|
||||
//Provide a hard limit on altitude
|
||||
upForce = if (entity.y >= altitudeLimit && upForce > 0) 0.0 else upForce
|
||||
}
|
||||
|
||||
val velocity = Vec3(state.rideVel.x , upForce, forwardForce)
|
||||
return velocity
|
||||
}
|
||||
|
||||
override fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
|
||||
if (!entity.isInWater && !entity.isUnderWater)
|
||||
{
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
val rollable = driver as? Rollable
|
||||
val state = getState(entity, ::DolphinLiquidState)
|
||||
|
||||
//TODO: Tie in handling
|
||||
val handling = this.getStat(entity, RidingStat.SKILL)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val rotationChangeRate = 10.0
|
||||
|
||||
//this should be changed to be speed maybe?
|
||||
val movingForce = driver.zza
|
||||
if (rollable != null) {
|
||||
var yawAngVel = 3 * sin(Math.toRadians(rollable.roll.toDouble())).toFloat()
|
||||
var pitchAngVel = -1 * Math.abs(sin(Math.toRadians(rollable.roll.toDouble())).toFloat())
|
||||
var yawForce = rotationChangeRate * sin(Math.toRadians(rollable.roll.toDouble()))
|
||||
//for a bit of correction on the rolls limit it to a quarter the amount
|
||||
var pitchForce = -0.35 * rotationChangeRate * abs(sin(Math.toRadians(rollable.roll.toDouble())))
|
||||
|
||||
//limit rotation modulation when pitched up heavily or pitched down heavily
|
||||
yawAngVel *= (abs(cos(Math.toRadians(rollable.pitch.toDouble())))).toFloat()
|
||||
pitchAngVel *= (abs(cos(Math.toRadians(rollable.pitch.toDouble())))).toFloat()
|
||||
//if you are not pressing forward then don't turn
|
||||
//yawAngVel *= movingForce
|
||||
//Ignore x,y,z its angular velocity:
|
||||
//yaw, pitch, roll
|
||||
return Vec3(yawAngVel.toDouble(), pitchAngVel.toDouble(), 0.0)
|
||||
yawForce *= abs(cos(Math.toRadians(rollable.pitch.toDouble())))
|
||||
pitchForce *= abs(cos(Math.toRadians(rollable.pitch.toDouble()))) * 1.5
|
||||
|
||||
return Vec3(yawForce, pitchForce, 0.0)
|
||||
}
|
||||
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override fun canJump(entity: PokemonEntity, driver: Player) = getRuntime(entity).resolveBoolean(canJump)
|
||||
override fun rotationOnMouseXY(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
yMouse: Double,
|
||||
xMouse: Double,
|
||||
yMouseSmoother: SmoothDouble,
|
||||
xMouseSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is Rollable) return Vec3.ZERO
|
||||
val rollable = driver as Rollable
|
||||
|
||||
override fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3 {
|
||||
val runtime = getRuntime(entity)
|
||||
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
|
||||
val jumpVector = jumpVector.map { runtime.resolveFloat(it) }
|
||||
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
|
||||
val state = getState(entity, ::DolphinLiquidState)
|
||||
val handling = this.getStat(entity, RidingStat.SKILL)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
val xInput = xMouseSmoother.getNewDeltaValue(xMouse * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
val yInput = yMouseSmoother.getNewDeltaValue(yMouse * 0.1 * invertPitch, deltaTime * smoothingSpeed);
|
||||
|
||||
//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
|
||||
val rotMin = 15.0
|
||||
var rollForce = xInput
|
||||
val rotLimit = max(handling * normalizeVal(state.rideVel.length(), 0.0, topSpeed).pow(3), rotMin)
|
||||
|
||||
//Limit roll by non linearly decreasing inputs towards
|
||||
// a rotation limit based on the current distance from
|
||||
// that rotation limit
|
||||
if (abs(rollable.roll + rollForce) < rotLimit) {
|
||||
if (sign(rollForce) == sign(rollable.roll).toDouble()) {
|
||||
val d = abs(abs(rollable.roll) - rotLimit)
|
||||
rollForce *= (d.pow(2)) / (rotLimit.pow(2))
|
||||
}
|
||||
} else if (sign(rollForce) == sign(rollable.roll).toDouble()) {
|
||||
rollForce = 0.0
|
||||
}
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * ( 1.0 - normalizeVal(state.rideVel.length(), 0.0, topSpeed).pow(3))
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(yawForce, yInput, rollForce)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(entity: PokemonEntity, driver: Player): Float {
|
||||
//Retrieve stamina from state
|
||||
val state = getState(entity, ::DolphinLiquidState)
|
||||
|
||||
return (state.stamina / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(entity: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRoll(entity: PokemonEntity) = true
|
||||
|
||||
override fun turnOffOnGround(entity: PokemonEntity): Boolean = true
|
||||
override fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val glideTopSpeed = getRuntime(entity).resolveDouble(glideTopSpeedExpr)
|
||||
val state = getState(entity, ::DolphinLiquidState)
|
||||
|
||||
override fun dismountOnShift(entity: PokemonEntity): Boolean = false
|
||||
//Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedGlideSpeed = normalizeVal(state.rideVel.length(), topSpeed, glideTopSpeed)
|
||||
|
||||
//Only ever want the fov change to be a max of 0.2 and for it to have non linear scaling.
|
||||
return 1.0f + normalizedGlideSpeed.pow(2).toFloat() * 0.2f
|
||||
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(entity: PokemonEntity): Boolean = false
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeString(this.speed.getString())
|
||||
buffer.writeString(this.canJump.getString())
|
||||
buffer.writeString(this.jumpVector[0].getString())
|
||||
buffer.writeString(this.jumpVector[1].getString())
|
||||
buffer.writeString(this.jumpVector[2].getString())
|
||||
buffer.writeString(this.driveFactor.getString())
|
||||
buffer.writeString(this.reverseDriveFactor.getString())
|
||||
buffer.writeString(this.strafeFactor.getString())
|
||||
buffer.writeDouble(this.lastVelocity.x)
|
||||
buffer.writeDouble(this.lastVelocity.y)
|
||||
buffer.writeDouble(this.lastVelocity.z)
|
||||
buffer.writeString(glideTopSpeedExpr.toString())
|
||||
buffer.writeString(infiniteStamina.toString())
|
||||
buffer.writeString(infiniteAltitude.toString())
|
||||
}
|
||||
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
this.speed = buffer.readString().asExpression()
|
||||
this.canJump = buffer.readString().asExpression()
|
||||
this.jumpVector = listOf(
|
||||
buffer.readString().asExpression(),
|
||||
buffer.readString().asExpression(),
|
||||
buffer.readString().asExpression()
|
||||
)
|
||||
this.driveFactor = buffer.readString().asExpression()
|
||||
this.reverseDriveFactor = buffer.readString().asExpression()
|
||||
this.strafeFactor = buffer.readString().asExpression()
|
||||
this.strafeFactor = buffer.readString().asExpression()
|
||||
val x = buffer.readDouble()
|
||||
val y = buffer.readDouble()
|
||||
val z = buffer.readDouble()
|
||||
this.lastVelocity = Vec3(x, y, z)
|
||||
glideTopSpeedExpr = buffer.readString().asExpression()
|
||||
infiniteStamina = buffer.readString().asExpression()
|
||||
infiniteAltitude = buffer.readString().asExpression()
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalizes the given value between a min and a max.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents x is at or below min
|
||||
* and 1.0 represents x is at or above it.
|
||||
*/
|
||||
fun normalizeVal(x: Double, min: Double, max: Double): Double {
|
||||
require(max > min) { "max must be greater than min" }
|
||||
return ((x - min) / (max - min)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
/*s
|
||||
* Calculates the change in the ride space vector due to player input and ride state
|
||||
*/
|
||||
fun calculateRideSpaceVel(entity: PokemonEntity, driver: Player, state: DolphinLiquidState) {
|
||||
|
||||
|
||||
//retrieve stats
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val glideTopSpeed = getRuntime(entity).resolveDouble(glideTopSpeedExpr)
|
||||
val accel = this.getStat(entity, RidingStat.ACCELERATION)
|
||||
val staminaStat = this.getStat(entity, RidingStat.STAMINA)
|
||||
|
||||
var glideSpeedChange = 0.00
|
||||
|
||||
val currSpeed = state.rideVel.length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina > 0.0) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
driver.zza > 0 && state.rideVel.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && state.rideVel.z < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
(state.rideVel.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
//Lateral movement based on driver input.
|
||||
val latTopSpeed = topSpeed / 2.0
|
||||
if (driver.xxa != 0.0f && state.stamina > 0.0) {
|
||||
state.rideVel = Vec3(
|
||||
(state.rideVel.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
|
||||
state.rideVel.y,
|
||||
state.rideVel.z)
|
||||
activeInput = true
|
||||
}
|
||||
else {
|
||||
state.rideVel = Vec3(
|
||||
lerp(state.rideVel.x, 0.0, latTopSpeed / 20.0),
|
||||
state.rideVel.y,
|
||||
state.rideVel.z)
|
||||
}
|
||||
|
||||
//Vertical movement based on driver input.
|
||||
val vertTopSpeed = topSpeed / 2.0
|
||||
val vertInput = when {
|
||||
Minecraft.getInstance().options.keyJump.isDown() -> 1.0
|
||||
Minecraft.getInstance().options.keyShift.isDown() -> -1.0
|
||||
else -> 0.0
|
||||
}
|
||||
|
||||
if (vertInput != 0.0 && state.stamina > 0.0) {
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
(state.rideVel.y + (accel * vertInput)).coerceIn(-vertTopSpeed, vertTopSpeed),
|
||||
state.rideVel.z)
|
||||
activeInput = true
|
||||
}
|
||||
else {
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
lerp(state.rideVel.y, 0.0, vertTopSpeed / 20.0),
|
||||
state.rideVel.z)
|
||||
}
|
||||
|
||||
//Check if the ride should be gliding
|
||||
if (activeInput && state.stamina > 0.0) {
|
||||
state.gliding = false
|
||||
}else {
|
||||
state.gliding = true
|
||||
}
|
||||
|
||||
//Only perform stamina logic if the ride does not have infinite stamina
|
||||
if (!getRuntime(entity).resolveBoolean(infiniteStamina)) {
|
||||
if (activeInput) {
|
||||
state.stamina -= (0.05 / staminaStat).toFloat()
|
||||
}
|
||||
|
||||
//Lose a base amount of stamina just for being airborne
|
||||
state.stamina -= (0.01 / staminaStat).toFloat()
|
||||
}
|
||||
else
|
||||
{
|
||||
state.stamina = 1.0f
|
||||
}
|
||||
|
||||
//air resistance
|
||||
//TODO: This method is very unrefined and will need to be an active point of testing
|
||||
/*
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
lerp( state.rideVel.z,0.0, topSpeed / ( 20.0 * 30.0)))
|
||||
*/
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -12,17 +12,13 @@ import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.CompositeState
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.adapters.RideControllerAdapter
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -77,6 +73,10 @@ class FallToFlightCompositeController : RideController {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
return getActiveController(entity).getStat(entity, stat)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
|
||||
+154
-42
@@ -9,19 +9,21 @@
|
||||
package com.cobblemon.mod.common.pokemon.riding.controllers
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.RidingAltPose
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.GenericLandState
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.JetAirState
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -49,20 +51,20 @@ class GenericLandController : RideController {
|
||||
private set
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
var sprintMod = "1.5".asExpression()
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LAND', 140.0, 20.0)".asExpression()
|
||||
private set
|
||||
var topSpeedExpr: 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
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'LAND', 30.0, 10.0)".asExpression()
|
||||
private set
|
||||
//Between a one block jump and a ten block jump
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 10.0, 1.0)".asExpression()
|
||||
private set
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
//Degrees per second
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'LAND', 135.0, 90.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'LAND', 0.65, 0.3)".asExpression(),
|
||||
// In seconds to max speed
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression(),
|
||||
// In Seconds
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'LAND', 30.0, 10.0)".asExpression(),
|
||||
// Block Jump Height
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'LAND', 10.0, 1.0)".asExpression()
|
||||
)
|
||||
|
||||
@Transient
|
||||
override val key: ResourceLocation = KEY
|
||||
@@ -87,13 +89,53 @@ class GenericLandController : RideController {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
val state = getState(entity, ::GenericLandState)
|
||||
return state.rideVel.length().toFloat()
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
|
||||
//Take the inverse so that it cancels out how
|
||||
//much the entity rotates.
|
||||
val turnAmount = calcRotAmount(entity, driver)
|
||||
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val state = getState(entity, ::GenericLandState)
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
val rotMod = Mth.wrapDegrees(driver.yRot - entity.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.rideVel.length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
//driver.yRot += (entity.riding.deltaRotation.y - turnAmount)
|
||||
//driver.setYHeadRot(driver.yHeadRot + (entity.riding.deltaRotation.y) - turnAmount)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
val f = Mth.wrapDegrees(driver.yRot - entity.yRot)
|
||||
val runtime = getRuntime(entity)
|
||||
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(entity: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
|
||||
val turnAmount = calcRotAmount(entity, driver)
|
||||
|
||||
return Vec2(driver.xRot, entity.yRot + turnAmount )
|
||||
}
|
||||
|
||||
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
|
||||
@@ -116,7 +158,7 @@ class GenericLandController : RideController {
|
||||
|
||||
//Jump the thang!
|
||||
if (Minecraft.getInstance().options.keyJump.isDown() && entity.onGround()) {
|
||||
state.rideVel = Vec3(state.rideVel.x, 2.0, state.rideVel.z)
|
||||
state.rideVel = Vec3(state.rideVel.x, 1.0, state.rideVel.z)
|
||||
}
|
||||
|
||||
//This is cheap.
|
||||
@@ -127,6 +169,8 @@ class GenericLandController : RideController {
|
||||
|
||||
//entity.deltaMovement = entity.deltaMovement.lerp(velocity, 1.0)
|
||||
//state.currVel = state.currVel.add( f.toDouble() / 20.0, gravity / 20.0 , g.toDouble() / 20.0)
|
||||
|
||||
println("Z speed: %.2f".format(state.rideVel.z) + "->" + "Z speed: %.2f".format(entity.deltaMovement.horizontalDistance()))
|
||||
return state.rideVel
|
||||
}
|
||||
|
||||
@@ -177,7 +221,28 @@ class GenericLandController : RideController {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun inertia(entity: PokemonEntity ): Double = 0.3
|
||||
override fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val sprintTopSpeed = topSpeed * getRuntime(entity).resolveDouble(sprintMod) //TODO: make it so sprint mod is global and likely molang json configurable
|
||||
val state = getState(entity, ::GenericLandState)
|
||||
|
||||
//Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedSprintSpeed = normalizeVal(state.rideVel.z, topSpeed, sprintTopSpeed)
|
||||
|
||||
//Only ever want the fov change to be a max of 0.2 and for it to have non linear scaling.
|
||||
val fovChange = 1.0f + normalizedSprintSpeed.pow(2).toFloat() * 0.2f
|
||||
return fovChange
|
||||
|
||||
}
|
||||
|
||||
override fun getActiveRidingAltPose(entity: PokemonEntity, driver: Player): RidingAltPose {
|
||||
//TODO: Should this be converted to a sprint flag?
|
||||
val isSprinting = Minecraft.getInstance().options.keySprint.isDown
|
||||
val pose = if (isSprinting) RidingAltPose.SPRINTING else RidingAltPose.NONE
|
||||
return pose
|
||||
}
|
||||
|
||||
override fun inertia(entity: PokemonEntity ): Double = 0.7
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
@@ -205,42 +270,89 @@ class GenericLandController : RideController {
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* Normalizes the given value between a min and a max.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents x is at or below min
|
||||
* and 1.0 represents x is at or above it.
|
||||
*/
|
||||
fun normalizeSpeed(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)
|
||||
fun normalizeVal(x: Double, min: Double, max: Double): Double {
|
||||
require(max > min) { "max must be greater than min" }
|
||||
return ((x - min) / (max - min)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(entity: PokemonEntity, driver: LivingEntity): Float {
|
||||
val state = getState(entity, ::GenericLandState)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
//In degrees per second
|
||||
val handling = this.getStat(entity, RidingStat.SKILL)
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
val rotDiff = Mth.wrapDegrees(driver.yRot - entity.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 more at higher speeds
|
||||
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVel.length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
//Ensure you only ever rotate as much difference as there is between the angles.
|
||||
val turnSpeed = handling.toFloat() / 20.0f * rotDiffMod * normSpeed
|
||||
val rotAmount = turnSpeed.coerceIn(-abs(rotDiff), abs(rotDiff))
|
||||
|
||||
return rotAmount
|
||||
}
|
||||
|
||||
fun calculateRideSpaceVel( entity: PokemonEntity, driver: Player, state: GenericLandState){
|
||||
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val accel = getRuntime(entity).resolveDouble(accelExpr)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val accel = this.getStat(entity, RidingStat.ACCELERATION)
|
||||
val speed = state.rideVel.length()
|
||||
|
||||
val minSpeed = 0.0
|
||||
val reverseMod = 1.0 / 3.0
|
||||
val isSprinting = Minecraft.getInstance().options.keySprint.isDown
|
||||
val sprintMod = getRuntime(entity).resolveDouble(sprintMod)
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza > 0.0 && speed <= topSpeed && state.stamina > 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)
|
||||
state.rideVel = Vec3(state.rideVel.x, state.rideVel.y, min(state.rideVel.z + (accel * accelMod) , topSpeed))
|
||||
}
|
||||
else if (driver.zza >= 0.0 && state.stamina == 0.0f || speed > topSpeed) {
|
||||
state.rideVel = Vec3(state.rideVel.x, state.rideVel.y, max(state.rideVel.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)
|
||||
if ((driver.zza != 0.0f && state.rideVel.z < topSpeed && !isSprinting) ||
|
||||
(driver.zza != 0.0f && state.rideVel.z < topSpeed * sprintMod && isSprinting)) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
driver.zza > 0 && state.rideVel.z > topSpeed && !isSprinting -> 0.0
|
||||
driver.zza < 0 && state.rideVel.z < (-topSpeed * reverseMod) && !isSprinting -> 0.0
|
||||
driver.zza > 0 && state.rideVel.z > topSpeed * sprintMod && isSprinting -> 0.0
|
||||
driver.zza < 0 && state.rideVel.z < (-topSpeed * sprintMod * reverseMod) && isSprinting -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
//Decelerate currently always a constant half of max acceleration.
|
||||
state.rideVel = Vec3(state.rideVel.x, state.rideVel.y, max( state.rideVel.z - ((accel * deccelMod) / 2) , minSpeed))
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
(state.rideVel.z + (accel * forwardInput.toDouble())))
|
||||
}
|
||||
//Otherwise if there is no input then apply deceleration
|
||||
else if (driver.zza == 0.0f) {
|
||||
//Make deceleration constant no matter the stats
|
||||
val decelRate = 1.0 / 20.0
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
lerp( state.rideVel.z, 0.0, decelRate )
|
||||
)
|
||||
}
|
||||
|
||||
state.rideVel = Vec3(state.rideVel.x, max(state.rideVel.y - 0.2, -1.0) , state.rideVel.z)
|
||||
|
||||
if (entity.onGround()) {
|
||||
//If on the ground then stop the increase of rideVel's gravity velocity
|
||||
if (!entity.onGround()) {
|
||||
state.rideVel = Vec3(state.rideVel.x, max(state.rideVel.y - 0.1, -1.0) , state.rideVel.z)
|
||||
} else {
|
||||
state.rideVel = Vec3(state.rideVel.x, 0.0 , state.rideVel.z)
|
||||
}
|
||||
|
||||
|
||||
+30
-20
@@ -8,20 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.riding.controllers
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -37,6 +32,20 @@ class GenericLiquidController : RideController {
|
||||
val KEY: ResourceLocation = cobblemonResource("swim/generic")
|
||||
}
|
||||
|
||||
override val key: ResourceLocation = KEY
|
||||
override val poseProvider: PoseProvider = PoseProvider(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { it.isSwimming && it.entityData.get(PokemonEntity.MOVING) })
|
||||
override val condition: (PokemonEntity) -> Boolean = { entity ->
|
||||
//This could be kinda weird... what if the top of the mon is in a fluid but the bottom isnt?
|
||||
Shapes.create(entity.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (entity.isInWater || entity.isUnderWater) {
|
||||
return@any true
|
||||
}
|
||||
val blockState = entity.level().getBlockState(it)
|
||||
return@any !blockState.fluidState.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
@@ -50,18 +59,19 @@ class GenericLiquidController : RideController {
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
|
||||
override val key: ResourceLocation = KEY
|
||||
override val poseProvider: PoseProvider = PoseProvider(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { it.isSwimming && it.entityData.get(PokemonEntity.MOVING) })
|
||||
override val condition: (PokemonEntity) -> Boolean = { entity ->
|
||||
//This could be kinda weird... what if the top of the mon is in a fluid but the bottom isnt?
|
||||
Shapes.create(entity.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (entity.isInWater || entity.isUnderWater) {
|
||||
return@any true
|
||||
}
|
||||
val blockState = entity.level().getBlockState(it)
|
||||
return@any !blockState.fluidState.isEmpty
|
||||
}
|
||||
//TODO: These are temp and need to be updated to real values
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'LIQUID', 135.0, 45.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'LIQUID', 0.6, 0.2)".asExpression(),
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'LIQUID', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression(),
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'LIQUID', 120.0, 20.0)".asExpression(),
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'LIQUID', 200.0, 128.0)".asExpression()
|
||||
)
|
||||
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
|
||||
+15
@@ -44,6 +44,21 @@ class GliderAirController : RideController {
|
||||
var canStrafe: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
//TODO: These are temp and need to be updated to real values
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression(),
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression(),
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression(),
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
)
|
||||
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
return getRuntime(entity).resolveFloat(speed)
|
||||
}
|
||||
|
||||
+15
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
@@ -63,6 +64,20 @@ class HelicopterAirController : RideController {
|
||||
var speed: Expression = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
//TODO: These are temp and need to be updated to real values
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression(),
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression(),
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression(),
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
)
|
||||
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
//Increased max speed to exaggerate movement.
|
||||
|
||||
+29
-40
@@ -9,12 +9,12 @@
|
||||
package com.cobblemon.mod.common.pokemon.riding.controllers
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.JetAirState
|
||||
@@ -36,35 +36,36 @@ class JetAirController : RideController {
|
||||
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
|
||||
var minSpeed: Expression = "1.2".asExpression()
|
||||
private set
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
|
||||
private set
|
||||
//TODO: Think about converting this to fully rely on the skillExpr evaluation
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 25.0, 8.0)".asExpression()
|
||||
private set
|
||||
var topSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.5, 1.0)".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', 'AIR', (1.0 / (20.0 * 1.0)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
// Between 60 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 60.0, 10.0)".asExpression()
|
||||
private set
|
||||
var jumpExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 300.0, 128.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Make configurable by json
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'AIR', 2.5, 1.0)".asExpression(),
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.0)), (1.0 / (20.0 * 5.0)))".asExpression(),
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'AIR', 60.0, 10.0)".asExpression(),
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'AIR', 300.0, 128.0)".asExpression()
|
||||
)
|
||||
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
|
||||
//retrieve stats
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val staminaStat = getRuntime(entity).resolveDouble(staminaExpr)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val staminaStat = this.getStat(entity, RidingStat.STAMINA)
|
||||
|
||||
//retrieve state
|
||||
val state = getState(entity, ::JetAirState)
|
||||
@@ -122,15 +123,13 @@ class JetAirController : RideController {
|
||||
//If stamina has run out then initiate forced glide down.
|
||||
upForce = if(state.stamina > 0.0) upForce else -0.7
|
||||
|
||||
val altitudeLimit = getRuntime(entity).resolveDouble(jumpExpr)
|
||||
val pushingHeightLimit = if(getRuntime(entity).resolveBoolean(infiniteAltitude)) false
|
||||
else (entity.y >= 128 && entity.xRot <= 0)
|
||||
val altitudeLimit = this.getStat(entity, RidingStat.JUMP)
|
||||
|
||||
|
||||
//Incorporate the altitude limiter.
|
||||
//Apply downwards force if limit is reached. Resist upwards force on a buffer of 30 blocks past the limit.
|
||||
upForce = if(pushingHeightLimit) upForce - upForce * ((entity.y - altitudeLimit) / 30) - 0.5
|
||||
else upForce
|
||||
//Only limit altitude if altitude is not infinite
|
||||
if (!getRuntime(entity).resolveBoolean(infiniteAltitude)) {
|
||||
//Provide a hard limit on altitude
|
||||
upForce = if (entity.y >= altitudeLimit && upForce > 0) 0.0 else upForce
|
||||
}
|
||||
|
||||
val velocity = Vec3(0.0 , upForce, forwardForce )
|
||||
|
||||
@@ -187,7 +186,7 @@ class JetAirController : RideController {
|
||||
state.currMouseYForce = (state.currMouseYForce + (0.0015 * yMouse * invertPitch)).coerceIn(-1.0, 1.0)
|
||||
|
||||
//Get handling in degrees per second
|
||||
var handling = getRuntime(entity).resolveDouble(handlingExpr)
|
||||
var handling = this.getStat(entity, RidingStat.SKILL)
|
||||
|
||||
//convert it to delta time
|
||||
handling *= (cappedDeltaTime)
|
||||
@@ -241,7 +240,7 @@ class JetAirController : RideController {
|
||||
override fun shouldRoll(entity: PokemonEntity) = true
|
||||
|
||||
override fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val minSpeed = getRuntime(entity).resolveDouble(minSpeed)
|
||||
val state = getState(entity, ::JetAirState)
|
||||
|
||||
@@ -258,12 +257,7 @@ class JetAirController : RideController {
|
||||
super.encode(buffer)
|
||||
buffer.writeString(gravity.toString())
|
||||
buffer.writeString(minSpeed.toString())
|
||||
buffer.writeString(handlingExpr.toString())
|
||||
buffer.writeString(handlingYawExpr.toString())
|
||||
buffer.writeString(topSpeedExpr.toString())
|
||||
buffer.writeString(accelExpr.toString())
|
||||
buffer.writeString(jumpExpr.toString())
|
||||
buffer.writeString(staminaExpr.toString())
|
||||
buffer.writeString(infiniteStamina.toString())
|
||||
buffer.writeString(infiniteAltitude.toString())
|
||||
}
|
||||
@@ -271,12 +265,7 @@ class JetAirController : RideController {
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
gravity = buffer.readString().asExpression()
|
||||
minSpeed = buffer.readString().asExpression()
|
||||
handlingExpr = buffer.readString().asExpression()
|
||||
handlingYawExpr = buffer.readString().asExpression()
|
||||
topSpeedExpr = buffer.readString().asExpression()
|
||||
accelExpr = buffer.readString().asExpression()
|
||||
jumpExpr = buffer.readString().asExpression()
|
||||
staminaExpr = buffer.readString().asExpression()
|
||||
infiniteStamina = buffer.readString().asExpression()
|
||||
infiniteAltitude = buffer.readString().asExpression()
|
||||
}
|
||||
@@ -290,9 +279,9 @@ class JetAirController : RideController {
|
||||
*/
|
||||
fun calculateRideSpaceVel( entity: PokemonEntity, driver: Player, state: JetAirState){
|
||||
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val accel = getRuntime(entity).resolveDouble(accelExpr)
|
||||
val altitudeLimit = getRuntime(entity).resolveDouble(jumpExpr)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val accel = this.getStat(entity, RidingStat.ACCELERATION)
|
||||
val altitudeLimit = this.getStat(entity, RidingStat.JUMP)
|
||||
val minSpeed = getRuntime(entity).resolveDouble(minSpeed)
|
||||
val speed = state.rideVel.length()
|
||||
|
||||
|
||||
+55
-18
@@ -12,6 +12,8 @@ import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.RidingAltPose
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -23,6 +25,7 @@ import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -66,20 +69,44 @@ class RunUpToFlightCompositeController : RideController {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
return getActiveController(entity).getStat(entity, stat)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
val state = getState(entity, ::RunUpToFlightCompositeState)
|
||||
if (state.activeController == flightController && entity.onGround() && state.timeTransitioned + 20 < entity.level().gameTime) {
|
||||
if (state.activeController == flightController && entity.onGround() &&
|
||||
state.timeTransitioned + 20 < entity.level().gameTime) {
|
||||
|
||||
//Pass the speed to the next state
|
||||
val flightState = flightController.getState(entity, ::BirdAirState)
|
||||
val groundState = landController.getState(entity, ::GenericLandState)
|
||||
groundState.currSpeed = flightState.currSpeed
|
||||
val flightState = flightController.getState( entity, ::BirdAirState )
|
||||
val groundState = landController.getState( entity, ::GenericLandState )
|
||||
groundState.rideVel = flightState.rideVel
|
||||
groundState.stamina = flightState.stamina
|
||||
|
||||
getState(entity, ::RunUpToFlightCompositeState).activeController = landController
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
|
||||
getState(entity, ::RunUpToFlightCompositeState).let {
|
||||
it.activeController = landController
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
|
||||
it.timeTransitioned = entity.level().gameTime
|
||||
}
|
||||
}
|
||||
else if (state.activeController == landController && Minecraft.getInstance().options.keyJump.isDown &&
|
||||
state.timeTransitioned + 20 < entity.level().gameTime) {
|
||||
|
||||
//Pass the speed to the next state
|
||||
val flightState = flightController.getState( entity, ::BirdAirState )
|
||||
val groundState = landController.getState( entity, ::GenericLandState )
|
||||
flightState.rideVel = groundState.rideVel
|
||||
flightState.stamina = groundState.stamina
|
||||
|
||||
getState(entity, ::RunUpToFlightCompositeState).let {
|
||||
it.activeController = flightController
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
|
||||
it.timeTransitioned = entity.level().gameTime
|
||||
}
|
||||
}
|
||||
|
||||
return getActiveController(entity).speed(entity, driver)
|
||||
@@ -89,6 +116,14 @@ class RunUpToFlightCompositeController : RideController {
|
||||
return getActiveController(entity).rotation(entity, driver)
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
return getActiveController(entity).updatePassengerRotation(entity, driver)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
return getActiveController(entity).clampPassengerRotation(entity, driver)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
@@ -101,6 +136,14 @@ class RunUpToFlightCompositeController : RideController {
|
||||
return getActiveController(entity).angRollVel(entity, driver, deltaTime)
|
||||
}
|
||||
|
||||
override fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
return getActiveController(entity).rideFovMult(entity, driver)
|
||||
}
|
||||
|
||||
override fun setRideBar(entity: PokemonEntity, driver: Player): Float {
|
||||
return getActiveController(entity).setRideBar(entity, driver)
|
||||
}
|
||||
|
||||
override fun canJump(entity: PokemonEntity, driver: Player): Boolean {
|
||||
return getActiveController(entity).canJump(entity, driver)
|
||||
}
|
||||
@@ -111,19 +154,9 @@ class RunUpToFlightCompositeController : RideController {
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
val controller = getActiveController(entity)
|
||||
if (controller == landController && jumpStrength >= getRuntime(entity).resolveInt(minimumJump)) {
|
||||
val state = getState(entity, ::CompositeState)
|
||||
val isJumping = Minecraft.getInstance().options.keyJump.isDown
|
||||
|
||||
//Pass the speed to the next state
|
||||
val flightState = flightController.getState(entity, ::BirdAirState )
|
||||
val groundState = landController.getState(entity, ::GenericLandState)
|
||||
flightState.currSpeed = groundState.currSpeed
|
||||
|
||||
getState(entity, ::RunUpToFlightCompositeState).let {
|
||||
it.activeController = flightController
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
|
||||
it.timeTransitioned = entity.level().gameTime
|
||||
}
|
||||
}
|
||||
return controller.jumpForce(entity, driver, jumpStrength)
|
||||
}
|
||||
|
||||
@@ -139,6 +172,10 @@ class RunUpToFlightCompositeController : RideController {
|
||||
|
||||
override fun useAngVelSmoothing(entity: PokemonEntity): Boolean = getActiveController(entity).useAngVelSmoothing(entity)
|
||||
|
||||
override fun getActiveRidingAltPose(entity: PokemonEntity, driver: Player): RidingAltPose {
|
||||
return getActiveController(entity).getActiveRidingAltPose(entity, driver)
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY
|
||||
(entity: PokemonEntity,
|
||||
driver: Player,
|
||||
|
||||
+16
@@ -12,6 +12,7 @@ import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -67,6 +68,10 @@ class RunUpToJetFlightCompositeController : RideController {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
return getActiveController(entity).getStat(entity, stat)
|
||||
}
|
||||
|
||||
//TODO: This composite controller needs to have the jet lift off at a certain speed.
|
||||
//maybe just pressing shift or space? Unsure, will need to test to see what works best.
|
||||
override fun speed(
|
||||
@@ -84,6 +89,7 @@ class RunUpToJetFlightCompositeController : RideController {
|
||||
val groundState = landController.getState(entity, ::GenericLandState)
|
||||
groundState.currSpeed = flightState.currSpeed
|
||||
groundState.stamina = flightState.stamina
|
||||
groundState.rideVel = flightState.rideVel
|
||||
|
||||
//Clear accumulated rotation input when transferring to ground input
|
||||
flightState.currMouseXForce = 0.0
|
||||
@@ -108,6 +114,7 @@ class RunUpToJetFlightCompositeController : RideController {
|
||||
val groundState = landController.getState(entity, ::GenericLandState)
|
||||
flightState.currSpeed = groundState.currSpeed
|
||||
flightState.stamina = groundState.stamina
|
||||
flightState.rideVel = groundState.rideVel
|
||||
|
||||
getState(entity, ::RunUpToFlightCompositeState).let {
|
||||
it.activeController = flightController
|
||||
@@ -123,6 +130,15 @@ class RunUpToJetFlightCompositeController : RideController {
|
||||
return getActiveController(entity).rotation(entity, driver)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
return getActiveController(entity).clampPassengerRotation(entity, driver)
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
return getActiveController(entity).updatePassengerRotation(entity, driver)
|
||||
}
|
||||
|
||||
|
||||
override fun velocity(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
|
||||
+18
@@ -8,13 +8,17 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.riding.controllers
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -44,10 +48,24 @@ class SwimDashController : RideController {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: These are temp and need to be updated to real values
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'LIQUID', 135.0, 45.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'LIQUID', 0.6, 0.2)".asExpression(),
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'LIQUID', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression(),
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'LIQUID', 120.0, 20.0)".asExpression(),
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'LIQUID', 200.0, 128.0)".asExpression()
|
||||
)
|
||||
|
||||
/** Indicates that we are currently enacting a dash, and that further movement inputs should be ignored */
|
||||
private var dashing = false
|
||||
private var ticks = 0
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
if(this.dashing) {
|
||||
if(this.ticks++ >= DASH_TICKS) {
|
||||
|
||||
+94
-49
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.riding.controllers
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
@@ -17,17 +18,13 @@ import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.riding.controllers.BirdAirController.Companion
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.VehicleLandState
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.client.Minecraft
|
||||
import kotlin.math.absoluteValue
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -36,49 +33,13 @@ import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sign
|
||||
|
||||
class VehicleLandController : RideController {
|
||||
companion object {
|
||||
val KEY: ResourceLocation = cobblemonResource("land/vehicle")
|
||||
|
||||
val MAXTOPSPEED = 1.0 // 20 bl/s
|
||||
val MINTOPSPEED = 0.35 // 7 bl/s
|
||||
//val MINSPEED = 0.25 // 5 bl/s
|
||||
|
||||
//Accel will lie between 1.0 second and 5.0 seconds
|
||||
val MAXACCEL = (MAXTOPSPEED ) / (20*3) //3.0 second to max speed
|
||||
val MINACCEL = (MAXTOPSPEED ) / (20*8) // 8 seconds to max speed
|
||||
|
||||
//Can rotate 90 degrees
|
||||
val MAXHANDLING = 90.0
|
||||
val MINHANDLING = 30.0
|
||||
|
||||
|
||||
val MAXYAWHANDLING = 16.0
|
||||
val MINYAWHANDLING = 8.0
|
||||
}
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
var speed = "0.3".asExpression()
|
||||
private set
|
||||
var driveFactor = "1.0".asExpression()
|
||||
private set
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var minimumSpeedToTurn = "0.1".asExpression()
|
||||
private set
|
||||
var rotationSpeed = "45/20".asExpression()
|
||||
private set
|
||||
var lookYawLimit = "101".asExpression()
|
||||
private set
|
||||
|
||||
var currSpeed = 0.0
|
||||
private set
|
||||
|
||||
@Transient
|
||||
override val key: ResourceLocation = KEY
|
||||
@Transient
|
||||
@@ -102,17 +63,57 @@ class VehicleLandController : RideController {
|
||||
}
|
||||
}
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
var speed = "0.3".asExpression()
|
||||
private set
|
||||
var driveFactor = "1.0".asExpression()
|
||||
private set
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var minimumSpeedToTurn = "0.1".asExpression()
|
||||
private set
|
||||
var rotationSpeed = "45/20".asExpression()
|
||||
private set
|
||||
var lookYawLimit = "101".asExpression()
|
||||
private set
|
||||
|
||||
var currSpeed = 0.0
|
||||
private set
|
||||
|
||||
//TODO: Replace these temp values
|
||||
private val statExpressions: Map<RidingStat, Expression> = mapOf(
|
||||
RidingStat.SKILL to "q.get_ride_stats('SKILL', 'LAND', 140.0, 20.0)".asExpression(),
|
||||
RidingStat.SPEED to "q.get_ride_stats('SPEED', 'LAND', 1.0, 0.3)".asExpression(),
|
||||
// In seconds to max speed
|
||||
RidingStat.ACCELERATION to "q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression(),
|
||||
// In Seconds
|
||||
RidingStat.STAMINA to "q.get_ride_stats('STAMINA', 'LAND', 30.0, 10.0)".asExpression(),
|
||||
// Block Jump Height
|
||||
RidingStat.JUMP to "q.get_ride_stats('JUMP', 'LAND', 10.0, 1.0)".asExpression()
|
||||
)
|
||||
|
||||
|
||||
|
||||
override fun getStat(entity: PokemonEntity, stat: RidingStat): Double {
|
||||
val expr = statExpressions[stat] ?: return 0.0
|
||||
return getRuntime(entity).resolveDouble(expr)
|
||||
}
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
|
||||
val topSpeed = entity.getRideStat(RidingStat.SPEED, RidingStyle.AIR, MINTOPSPEED, MAXTOPSPEED)
|
||||
val accel = entity.getRideStat(RidingStat.ACCELERATION, RidingStyle.AIR, MINACCEL, MAXACCEL)
|
||||
val topSpeed = this.getStat(entity, RidingStat.SPEED)
|
||||
val accel = this.getStat(entity, RidingStat.ACCELERATION)
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza > 0.0 && currSpeed < topSpeed) {
|
||||
currSpeed = min(currSpeed + accel , topSpeed)
|
||||
} else if (driver.zza < 0.0 && currSpeed > 0.0) {
|
||||
//Decelerate is now always a constant half of max acceleration.
|
||||
currSpeed = max(currSpeed - (MAXACCEL / 2), 0.0)
|
||||
currSpeed = max(currSpeed - (accel / 2), 0.0)
|
||||
}
|
||||
|
||||
return currSpeed.toFloat()
|
||||
@@ -120,7 +121,51 @@ class VehicleLandController : RideController {
|
||||
|
||||
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
val rotationDegrees = driver.xxa * getRuntime(entity).resolveFloat(this.rotationSpeed)
|
||||
return Vec2(driver.xRot, entity.yRot - rotationDegrees)
|
||||
val state = getState(entity, ::VehicleLandState)
|
||||
|
||||
if( Minecraft.getInstance().options.keyJump.isDown() ){
|
||||
//If the current drift has not been set and the car is rotating then set drift
|
||||
if( state.currDrift == 0.0 && rotationDegrees != 0.0f) {
|
||||
//Set to base value which will be half.
|
||||
state.currDrift = sign(rotationDegrees) * 2.5
|
||||
state.turnSmoother.reset()
|
||||
}
|
||||
|
||||
//Calculate any changes to drift
|
||||
val driftChangeRate = (1.0 / (20.0 * 0.15))
|
||||
|
||||
//If Drift is negative already
|
||||
if(state.currDrift < 0) {
|
||||
state.currDrift = (state.currDrift + (sign(rotationDegrees) * driftChangeRate)).coerceIn(-5.0, -1.0)
|
||||
}else{
|
||||
state.currDrift = (state.currDrift + (sign(rotationDegrees) * driftChangeRate)).coerceIn(1.0, 5.0)
|
||||
}
|
||||
return Vec2(driver.xRot, entity.yRot - state.currDrift.toFloat())
|
||||
}
|
||||
//If the drift key is not held then reset the curr drift to 0 and use normal rotation
|
||||
else{
|
||||
//If the drift key has just been released perform boost addition and drift reset
|
||||
if( state.currDrift != 0.0){
|
||||
state.turnSmoother.reset()
|
||||
state.currDrift = 0.0
|
||||
state.driftBoost = min(state.driftBoost + 1.0, 2.0)
|
||||
driver.level().playSound(
|
||||
null as Player?,
|
||||
driver.getX(),
|
||||
driver.getY(),
|
||||
driver.getZ(), SoundEvents.PLAYER_ATTACK_WEAK,
|
||||
driver.getSoundSource(), 1.0f, 0.2f
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
//Restrict turning while boost is active
|
||||
val boostRotDebuff = if( state.driftBoost != 0.0 ) 0.5f else 1.0f
|
||||
|
||||
return Vec2(driver.xRot, entity.yRot - (rotationDegrees * boostRotDebuff) )
|
||||
//return Vec2(driver.xRot, state.turnSmoother.getNewDeltaValue((entity.yRot - rotationDegrees).toDouble(), 1.0).toFloat())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
|
||||
|
||||
+3
-2
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
data class BirdAirState(val entity: PokemonEntity) : RidingState {
|
||||
var currSpeed: Double = 0.0
|
||||
var lastVelocity: Vec3 = Vec3(0.0, 0.0, 0.0)
|
||||
override var rideVel: Vec3 = Vec3.ZERO
|
||||
override var stamina: Float = 1.0f
|
||||
var gliding: Boolean = false
|
||||
}
|
||||
+3
@@ -11,8 +11,11 @@ package com.cobblemon.mod.common.pokemon.riding.states
|
||||
import com.cobblemon.mod.common.api.riding.RidingState
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
open class CompositeState(pokemonEntity: PokemonEntity) : RidingState {
|
||||
override var rideVel: Vec3 = Vec3.ZERO
|
||||
override var stamina: Float = 1.0f
|
||||
var activeController: RideController? = null
|
||||
var timeTransitioned = -100L
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.pokemon.riding.states
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.RidingState
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
data class DolphinLiquidState(val entity: PokemonEntity) : RidingState {
|
||||
override var rideVel: Vec3 = Vec3.ZERO
|
||||
override var stamina: Float = 1.0f
|
||||
var currSpeed: Double = 0.0
|
||||
var gliding: Boolean = false
|
||||
}
|
||||
+2
-2
@@ -13,7 +13,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
data class GenericLandState(val entity: PokemonEntity) : RidingState {
|
||||
override var rideVel: Vec3 = Vec3.ZERO
|
||||
override var stamina: Float = 1.0f
|
||||
var currSpeed: Double = 0.0
|
||||
var rideVel: Vec3 = Vec3.ZERO
|
||||
var stamina: Float = 1.0f
|
||||
}
|
||||
+2
-2
@@ -13,9 +13,9 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
data class JetAirState(val entity: PokemonEntity) : RidingState {
|
||||
override var rideVel: Vec3 = Vec3.ZERO
|
||||
override var stamina: Float = 1.0f
|
||||
var currSpeed: Double = 0.0
|
||||
var stamina: Float = 1.0f
|
||||
var rideVel: Vec3 = Vec3.ZERO
|
||||
var currMouseXForce: Double = 0.0
|
||||
var currMouseYForce: Double = 0.0
|
||||
}
|
||||
+3
@@ -9,7 +9,10 @@
|
||||
package com.cobblemon.mod.common.pokemon.riding.states
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class RunUpToFlightCompositeState(pokemonEntity: PokemonEntity) : CompositeState(pokemonEntity) {
|
||||
override var rideVel: Vec3 = Vec3.ZERO
|
||||
override var stamina: Float = 1.0f
|
||||
var currSpeed: Double = 0.0
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.pokemon.riding.states
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.RidingState
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
data class VehicleLandState(val entity: PokemonEntity) : RidingState {
|
||||
override var rideVel: Vec3 = Vec3.ZERO
|
||||
override var stamina: Float = 1.0f
|
||||
var currDrift: Double = 0.0
|
||||
var driftBoost: Double = 0.0
|
||||
var turnSmoother: SmoothDouble = SmoothDouble()
|
||||
}
|
||||
+278
-101
@@ -124,8 +124,14 @@
|
||||
},
|
||||
"pokeball": {
|
||||
"scale": {
|
||||
"0.4583": {"pre": [0, 0, 0], "post": [0.3, 0.3, 0.3]},
|
||||
"0.5417": {"pre": [0.3, 0.3, 0.3], "post": [0.3, 0.3, 0.3]},
|
||||
"0.4583": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.3, 0.3, 0.3]
|
||||
},
|
||||
"0.5417": {
|
||||
"pre": [0.3, 0.3, 0.3],
|
||||
"post": [0.3, 0.3, 0.3]
|
||||
},
|
||||
"0.7083": [1, 1, 1]
|
||||
}
|
||||
},
|
||||
@@ -556,105 +562,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.trainer_generic.send_out": {
|
||||
"animation_length": 3.625,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": {
|
||||
"0.0": [1, 0, 0],
|
||||
"0.9375": [1, 0, 0],
|
||||
"1.375": [1, -7.5, 0],
|
||||
"2.875": [1, -7.5, 0],
|
||||
"3.375": [1, 0, 0],
|
||||
"3.625": [1, 0, 0]
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": {
|
||||
"0.0": [-1, 0, 0],
|
||||
"0.9375": [-1, 0, 0],
|
||||
"1.375": [-1, 7.5, 0],
|
||||
"2.875": [-1, 7.5, 0],
|
||||
"3.375": [-1, 0, 0],
|
||||
"3.625": [-1, 0, 0]
|
||||
}
|
||||
},
|
||||
"arm_ball": {
|
||||
"rotation": {
|
||||
"0.0": [3, 0, 3.5],
|
||||
"0.5": [3, 0, 3.5],
|
||||
"0.9375": {
|
||||
"pre": [14.5, 2.5, -17.5],
|
||||
"post": [14.5, 2.5, -17.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.125": {
|
||||
"post": [5, 2.5, -0.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.375": [-91, 7.5, 0],
|
||||
"2.875": [-91, 7.5, 0],
|
||||
"3.1875": {
|
||||
"pre": [5, 2.5, -0.5],
|
||||
"post": [5, 2.5, -0.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"3.375": {
|
||||
"post": [14.5, 2.5, -17.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"3.625": [3, 0, 3.5]
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0, 0.1, 0],
|
||||
"3.625": [0, 0.1, 0]
|
||||
}
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": {
|
||||
"0.0": [3, 0, -3.5],
|
||||
"0.9375": [3, 0, -3.5],
|
||||
"1.375": [13, 0, -6],
|
||||
"2.875": [13, 0, -6],
|
||||
"3.375": [3, 0, -3.5]
|
||||
},
|
||||
"position": [0, 0.1, 0]
|
||||
},
|
||||
"pokeball": {
|
||||
"scale": {
|
||||
"0.9375": {"pre": [0, 0, 0], "post": [0.3, 0.3, 0.3]},
|
||||
"1.0": {"pre": [0.3, 0.3, 0.3], "post": [0.3, 0.3, 0.3]},
|
||||
"1.1875": [1, 1, 1],
|
||||
"3.0625": [1, 1, 1],
|
||||
"3.25": [0.4, 0.4, 0.4],
|
||||
"3.375": {"pre": [0.4, 0.4, 0.4], "post": [0, 0, 0]}
|
||||
}
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": {
|
||||
"0.9375": [0, 8, 0.5],
|
||||
"1.375": [1, 10, 0.5],
|
||||
"2.875": [1, 10, 0.5],
|
||||
"3.375": [0, 8, 0.5]
|
||||
},
|
||||
"position": {
|
||||
"0.9375": [-0.2, 0, 0],
|
||||
"1.375": [-0.2, 0, -0.2],
|
||||
"2.875": [-0.2, 0, -0.2],
|
||||
"3.375": [-0.2, 0, 0]
|
||||
}
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": {
|
||||
"0.9375": [0, -8, -0.5],
|
||||
"1.375": [0, -10, -0.5],
|
||||
"2.875": [0, -10, -0.5],
|
||||
"3.375": [0, -8, -0.5]
|
||||
},
|
||||
"position": [0.2, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.trainer_generic.command": {
|
||||
"animation_length": 2,
|
||||
"bones": {
|
||||
@@ -996,6 +903,276 @@
|
||||
"scale": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.trainer_generic.return": {
|
||||
"animation_length": 3.625,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": {
|
||||
"0.0": [1, 0, 0],
|
||||
"0.9375": [1, 0, 0],
|
||||
"1.375": [1, -7.5, 0],
|
||||
"2.875": [1, -7.5, 0],
|
||||
"3.375": [1, 0, 0],
|
||||
"3.625": [1, 0, 0]
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": {
|
||||
"0.0": [-1, 0, 0],
|
||||
"0.9375": [-1, 0, 0],
|
||||
"1.375": [-1, 7.5, 0],
|
||||
"2.875": [-1, 7.5, 0],
|
||||
"3.375": [-1, 0, 0],
|
||||
"3.625": [-1, 0, 0]
|
||||
}
|
||||
},
|
||||
"arm_ball": {
|
||||
"rotation": {
|
||||
"0.0": [3, 0, 3.5],
|
||||
"0.5": [3, 0, 3.5],
|
||||
"0.9375": {
|
||||
"pre": [14.5, 2.5, -17.5],
|
||||
"post": [14.5, 2.5, -17.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.125": {
|
||||
"post": [5, 2.5, -0.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.375": [-91, 7.5, 0],
|
||||
"2.875": [-91, 7.5, 0],
|
||||
"3.1875": {
|
||||
"pre": [5, 2.5, -0.5],
|
||||
"post": [5, 2.5, -0.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"3.375": {
|
||||
"post": [14.5, 2.5, -17.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"3.625": [3, 0, 3.5]
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0, 0.1, 0],
|
||||
"3.625": [0, 0.1, 0]
|
||||
}
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": {
|
||||
"0.0": [3, 0, -3.5],
|
||||
"0.9375": [3, 0, -3.5],
|
||||
"1.375": [13, 0, -6],
|
||||
"2.875": [13, 0, -6],
|
||||
"3.375": [3, 0, -3.5]
|
||||
},
|
||||
"position": [0, 0.1, 0]
|
||||
},
|
||||
"pokeball": {
|
||||
"scale": {
|
||||
"0.9375": {
|
||||
"pre": [0, 0, 0],
|
||||
"post": [0.3, 0.3, 0.3]
|
||||
},
|
||||
"1.0": [0.3, 0.3, 0.3],
|
||||
"1.1875": [1, 1, 1],
|
||||
"3.0625": [1, 1, 1],
|
||||
"3.25": [0.4, 0.4, 0.4],
|
||||
"3.375": {
|
||||
"pre": [0.4, 0.4, 0.4],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": {
|
||||
"0.9375": [0, 8, 0.5],
|
||||
"1.375": [1, 10, 0.5],
|
||||
"2.875": [1, 10, 0.5],
|
||||
"3.375": [0, 8, 0.5]
|
||||
},
|
||||
"position": {
|
||||
"0.9375": [-0.2, 0, 0],
|
||||
"1.375": [-0.2, 0, -0.2],
|
||||
"2.875": [-0.2, 0, -0.2],
|
||||
"3.375": [-0.2, 0, 0]
|
||||
}
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": {
|
||||
"0.9375": [0, -8, -0.5],
|
||||
"1.375": [0, -10, -0.5],
|
||||
"2.875": [0, -10, -0.5],
|
||||
"3.375": [0, -8, -0.5]
|
||||
},
|
||||
"position": [0.2, 0, 0]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"1.0": "q.render_item(v.actioning_pokemon_ball, 'item_right');",
|
||||
"3.3125": "q.clear_items();"
|
||||
}
|
||||
},
|
||||
"animation.trainer_generic.send_out": {
|
||||
"animation_length": 2.875,
|
||||
"bones": {
|
||||
"torso_crouch": {
|
||||
"rotation": {
|
||||
"0.9167": [0, 0, 0],
|
||||
"1.4167": {
|
||||
"pre": [0, 10, 0],
|
||||
"post": [0, 10, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.5417": {
|
||||
"post": [0, -10, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.7917": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"arms": {
|
||||
"rotation": {
|
||||
"0.9167": [0, 0, 0],
|
||||
"1.4167": {
|
||||
"pre": [0, 10, 0],
|
||||
"post": [0, 10, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.5417": {
|
||||
"post": [0, -10, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.7917": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"torso_item_right": {
|
||||
"rotation": [0.5, 0, 0]
|
||||
},
|
||||
"arms_item_right": {
|
||||
"rotation": {
|
||||
"0.9167": [0, 0, 0],
|
||||
"1.4167": {
|
||||
"pre": [0, 10, 0],
|
||||
"post": [0, 10, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.5417": {
|
||||
"post": [0, -10, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.7917": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"arm_item_right": {
|
||||
"rotation": {
|
||||
"0.9167": [1, 0, 2.5],
|
||||
"1.4167": {
|
||||
"pre": [-85, 10, -10],
|
||||
"post": [-85, 10, -10],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.5417": {
|
||||
"post": [-72.5, -30, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.7917": [1, 0, 2.5]
|
||||
},
|
||||
"position": [0, 0.1, 0]
|
||||
},
|
||||
"torso_item_left": {
|
||||
"rotation": [0.5, 0, 0]
|
||||
},
|
||||
"arms_item_left": {
|
||||
"rotation": {
|
||||
"0.9167": [0, 0, 0],
|
||||
"1.4167": {
|
||||
"pre": [0, 10, 0],
|
||||
"post": [0, 10, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.5417": {
|
||||
"post": [0, -10, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.7917": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
"arm_item_left": {
|
||||
"rotation": {
|
||||
"0.9167": [1, 0, -2.5],
|
||||
"1.4167": {
|
||||
"pre": [4, 0, 0],
|
||||
"post": [4, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.5417": {
|
||||
"post": [-8, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.7917": [1, 0, -2.5]
|
||||
},
|
||||
"position": [0, 0.1, 0]
|
||||
},
|
||||
"torso": {
|
||||
"rotation": [0.5, 0, 0]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [-0.5, 0, 0]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": {
|
||||
"0.9167": [1, 0, 2.5],
|
||||
"1.4167": {
|
||||
"pre": [-85, 10, -10],
|
||||
"post": [-85, 10, -10],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.5417": {
|
||||
"post": [-72.5, -30, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.7917": [1, 0, 2.5]
|
||||
},
|
||||
"position": [0, 0.1, 0]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": {
|
||||
"0.9167": [1, 0, -2.5],
|
||||
"1.4167": {
|
||||
"pre": [4, 0, 0],
|
||||
"post": [4, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.5417": {
|
||||
"post": [-8, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.7917": [1, 0, -2.5]
|
||||
},
|
||||
"position": [0, 0.1, 0]
|
||||
},
|
||||
"leg_right": {
|
||||
"rotation": [0, 2, 0.5],
|
||||
"position": [-0.05, 0, 0]
|
||||
},
|
||||
"leg_left": {
|
||||
"rotation": [0, -2, -0.5],
|
||||
"position": [0.05, 0, 0]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.render_item(v.actioning_pokemon_ball, 'item_right');",
|
||||
"1.5833": "q.render_item('air', 'item_right');"
|
||||
}
|
||||
}
|
||||
},
|
||||
"geometry.animations": {
|
||||
"texturewidth": 64,
|
||||
"textureheight": 64
|
||||
},
|
||||
"geometry.unknown": {
|
||||
"texturewidth": 16,
|
||||
"textureheight": 16
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,14 @@
|
||||
{"origin": [-7, 12, -2], "size": [3, 12, 4], "inflate": 0.25, "uv": [40, 32]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_right",
|
||||
"parent": "arm_right",
|
||||
"pivot": [-5.5, 12, -2],
|
||||
"locators": {
|
||||
"item_right": [-5.5, 12, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pokeball",
|
||||
"parent": "arm_ball",
|
||||
@@ -99,6 +107,14 @@
|
||||
{"origin": [4, 12, -2], "size": [3, 12, 4], "inflate": 0.25, "uv": [48, 48]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_left",
|
||||
"parent": "arm_left",
|
||||
"pivot": [5.5, 12, -2],
|
||||
"locators": {
|
||||
"item_left": [5.5, 12, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leg_right",
|
||||
"parent": "body",
|
||||
|
||||
@@ -97,6 +97,14 @@
|
||||
{"origin": [-7, 12, -2], "size": [3, 11, 4], "inflate": 0.25, "uv": [40, 31]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_right",
|
||||
"parent": "arm_right",
|
||||
"pivot": [-5.5, 12, -2],
|
||||
"locators": {
|
||||
"item_right": [-5.5, 12, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arm_left",
|
||||
"parent": "torso",
|
||||
@@ -106,6 +114,14 @@
|
||||
{"origin": [4, 12, -2], "size": [3, 11, 4], "inflate": 0.25, "uv": [46, 48]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_left",
|
||||
"parent": "arm_left",
|
||||
"pivot": [5.5, 12, -2],
|
||||
"locators": {
|
||||
"item_left": [5.5, 12, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leg_right",
|
||||
"parent": "body",
|
||||
|
||||
@@ -81,6 +81,14 @@
|
||||
{"origin": [-8, 12, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [40, 32]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_right",
|
||||
"parent": "arm_right",
|
||||
"pivot": [-6, 12, -2],
|
||||
"locators": {
|
||||
"item_right": [-6, 12, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pokeball",
|
||||
"parent": "arm_ball",
|
||||
@@ -99,6 +107,14 @@
|
||||
{"origin": [4, 12, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [48, 48]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_left",
|
||||
"parent": "arm_left",
|
||||
"pivot": [6, 12, -2],
|
||||
"locators": {
|
||||
"item_left": [6, 12, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leg_right",
|
||||
"parent": "body",
|
||||
|
||||
@@ -79,29 +79,18 @@
|
||||
"cubes": [
|
||||
{"origin": [-8, 12, -2], "size": [4, 12, 4], "uv": [40, 16]},
|
||||
{"origin": [-8, 12, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [40, 32]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pokeball",
|
||||
"parent": "arm_ball",
|
||||
"pivot": [-6, 12, 0],
|
||||
"cubes": [
|
||||
{"origin": [-8, 8, -2], "size": [4, 2, 4], "pivot": [-6, 10, 0], "rotation": [90, 0, 0], "uv": [0, 122]}
|
||||
],
|
||||
"locators": {
|
||||
"beam": [-6, 8, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pokeball_lid",
|
||||
"parent": "pokeball",
|
||||
"pivot": [-6, 10, 0],
|
||||
"rotation": [90, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-6.5, 9.5, -2.02], "size": [1, 1, 0], "uv": [0, 123]},
|
||||
{"origin": [-7, 9, -2.01], "size": [2, 2, 0], "uv": [0, 124]},
|
||||
{"origin": [-8, 10, -2], "size": [4, 2, 4], "uv": [0, 116]}
|
||||
]
|
||||
"name": "item_right",
|
||||
"parent": "arm_right",
|
||||
"pivot": [-6, 12, -2],
|
||||
"locators": {
|
||||
"item_right": [-6, 12, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arm_left",
|
||||
@@ -112,6 +101,14 @@
|
||||
{"origin": [4, 12, -2], "size": [4, 12, 4], "inflate": 0.25, "uv": [48, 48]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_left",
|
||||
"parent": "arm_left",
|
||||
"pivot": [6, 12, -2],
|
||||
"locators": {
|
||||
"item_left": [6, 12, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leg_right",
|
||||
"parent": "body",
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
"portraitTranslation": [0.0, 1.1, 0.0],
|
||||
"profileScale": 1.0,
|
||||
"profileTranslation": [0.0, -0.5, 0.0],
|
||||
"properties": {
|
||||
"item_display_context": "THIRD_PERSON_RIGHT_HAND",
|
||||
"item_right_display_context": "THIRD_PERSON_RIGHT_HAND",
|
||||
"item_left_display_context": "THIRD_PERSON_LEFT_HAND"
|
||||
},
|
||||
"animations": {
|
||||
"win": "q.bedrock_primary('trainer_generic', 'win', q.curve('symmetrical_wide'))",
|
||||
"lose": "q.bedrock_primary('trainer_generic', 'lose', q.curve('symmetrical_wide'))",
|
||||
"send_out": "q.bedrock_primary('trainer_generic', 'send_out', q.curve('symmetrical'), q.exclude_labels('look'))",
|
||||
"recall": "q.bedrock_primary('trainer_generic', 'send_out', q.curve('symmetrical_wide'), q.exclude_labels('look'))",
|
||||
"recall": "q.bedrock_primary('trainer_generic', 'return', q.curve('symmetrical_wide'), q.exclude_labels('look'))",
|
||||
"punch_left": "q.primary_animation(q.punch('head', 'body', 'arm_left', 'arm_right', false), q.curve('symmetrical_wide'), q.exclude_labels('look'))",
|
||||
"punch_right": "q.primary_animation(q.punch('head', 'body', 'arm_right', 'arm_left', true), q.curve('symmetrical_wide'), q.exclude_labels('look'))"
|
||||
},
|
||||
|
||||
+1
-1
@@ -14543,7 +14543,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": {
|
||||
|
||||
+158
-125
@@ -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": 7,
|
||||
"visible_bounds_offset": [0, 2.5, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
@@ -20,7 +20,7 @@
|
||||
"parent": "charizard",
|
||||
"pivot": [0, 0, -1],
|
||||
"locators": {
|
||||
"root": [0, 0, -1]
|
||||
"root": [0, 0, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -28,7 +28,7 @@
|
||||
"parent": "charizard",
|
||||
"pivot": [0, 41, -1],
|
||||
"locators": {
|
||||
"top": [0, 41, -1]
|
||||
"top": [0, 41, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -116,8 +116,7 @@
|
||||
{
|
||||
"name": "head_correction",
|
||||
"parent": "head",
|
||||
"pivot": [0, 43.5, -0.5],
|
||||
"rotation": [-95, 0, 0]
|
||||
"pivot": [0, 43.5, -0.5]
|
||||
},
|
||||
{
|
||||
"name": "head_ai",
|
||||
@@ -128,15 +127,20 @@
|
||||
"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": [-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]}
|
||||
{"origin": [-3.5, 41.5, -4], "size": [7, 4, 2], "uv": [95, 64]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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",
|
||||
@@ -146,59 +150,51 @@
|
||||
"head": [0, 46.5, 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_mouth",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 48.75, -3],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"mouth": [0, 48.75, -3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_special_attack",
|
||||
"parent": "head_angle",
|
||||
"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": "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",
|
||||
"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],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"mouth": [0, 45.75, -2],
|
||||
"special": [0, 45.75, -2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eyes",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, -3.5, 1.5]
|
||||
},
|
||||
{
|
||||
"name": "brow",
|
||||
"parent": "eyes",
|
||||
"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_right",
|
||||
"parent": "eye",
|
||||
"parent": "eyes",
|
||||
"pivot": [-2.75, 47.75, 0.875],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 47.5, 0], "size": [2, 1, 2], "inflate": 0.01, "uv": [106, 36]},
|
||||
@@ -226,7 +222,7 @@
|
||||
},
|
||||
{
|
||||
"name": "eye_left",
|
||||
"parent": "eye",
|
||||
"parent": "eyes",
|
||||
"pivot": [2.75, 47.75, 0.875],
|
||||
"cubes": [
|
||||
{"origin": [1.5, 47.5, 0], "size": [2, 1, 2], "inflate": 0.01, "uv": [44, 82]},
|
||||
@@ -255,6 +251,91 @@
|
||||
{"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",
|
||||
@@ -300,72 +381,6 @@
|
||||
"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",
|
||||
@@ -403,6 +418,14 @@
|
||||
{"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",
|
||||
@@ -913,6 +936,14 @@
|
||||
{"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",
|
||||
@@ -945,9 +976,10 @@
|
||||
{
|
||||
"name": "locator_foot_primary",
|
||||
"parent": "foot_right",
|
||||
"pivot": [-9, 1.5, -7],
|
||||
"pivot": [-9, 1.5, -5],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_primary": [-9, 1.5, -7]
|
||||
"foot_primary": [-9, 1.5, -5]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1009,9 +1041,10 @@
|
||||
{
|
||||
"name": "locator_foot_secondary",
|
||||
"parent": "foot_left",
|
||||
"pivot": [9, 1.5, -7],
|
||||
"pivot": [9, 1.5, -5],
|
||||
"rotation": [90, 0, 0],
|
||||
"locators": {
|
||||
"foot_secondary": [9, 1.5, -7]
|
||||
"foot_secondary": [9, 1.5, -5]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
+4
-1
@@ -34,7 +34,10 @@
|
||||
"pivot": [0, 26.2, 0],
|
||||
"cubes": [
|
||||
{"origin": [-5, 25.2, -4], "size": [10, 7, 8], "inflate": 0.01, "uv": [26, 32]}
|
||||
]
|
||||
],
|
||||
"locators": {
|
||||
"seat_1": [0, 28, 4]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "fin",
|
||||
|
||||
+4
-1
@@ -26,7 +26,10 @@
|
||||
"pivot": [0, 24.5, -1],
|
||||
"cubes": [
|
||||
{"origin": [-6, 18.5, -13.75], "size": [12, 12, 26], "uv": [52, 39]}
|
||||
]
|
||||
],
|
||||
"locators": {
|
||||
"seat_1": [0, 30, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "neck",
|
||||
|
||||
+25
-1
@@ -86,12 +86,36 @@
|
||||
"fly": {
|
||||
"poseTypes": ["FLY"],
|
||||
"isBattle": false,
|
||||
"animations": ["q.look('head_ai')", "q.bedrock('charizard', 'air_fly')"],
|
||||
"condition": "!q.riding_alt_pose('GLIDING')",
|
||||
"animations": [
|
||||
"q.look('head_ai')",
|
||||
"q.bedrock('charizard', 'air_fly')",
|
||||
{
|
||||
"condition": "q.has_passenger",
|
||||
"animation": "q.bedrock('charizard', 'riding_look')"
|
||||
}
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('charizard', 'blink')",
|
||||
"q.bedrock_quirk('charizard', 'air_fly_quirk')"
|
||||
]
|
||||
},
|
||||
"glide": {
|
||||
"poseTypes": ["FLY"],
|
||||
"isBattle": false,
|
||||
"condition": "q.riding_alt_pose('GLIDING')",
|
||||
"animations": [
|
||||
"q.look('head_ai')",
|
||||
"q.bedrock('charizard', 'air_glide_TEST')",
|
||||
{
|
||||
"condition": "q.has_passenger",
|
||||
"animation": "q.bedrock('charizard', 'riding_look')"
|
||||
}
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('charizard', 'blink')"
|
||||
]
|
||||
},
|
||||
"surface_idle": {
|
||||
"poseTypes": ["STAND", "FLOAT"],
|
||||
"isTouchingWater": true,
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"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": {
|
||||
"portrait": {
|
||||
"poseTypes": ["PORTRAIT", "PROFILE"],
|
||||
"isBattle": false,
|
||||
"isTouchingWater": false,
|
||||
"animations": [
|
||||
"q.look('head_ai')",
|
||||
"q.bedrock('mudsdale', 'ground_idle')"
|
||||
],
|
||||
"quirks": ["q.bedrock_quirk('mudsdale', 'blink')"]
|
||||
},
|
||||
"standing": {
|
||||
"poseTypes": ["STAND", "NONE"],
|
||||
"isBattle": false,
|
||||
"isTouchingWater": false,
|
||||
"animations": [
|
||||
"q.look('head_ai')",
|
||||
"q.bedrock('mudsdale', 'ground_idle')"
|
||||
],
|
||||
"quirks": ["q.bedrock_quirk('mudsdale', 'blink')"]
|
||||
},
|
||||
"walking": {
|
||||
"poseTypes": ["WALK"],
|
||||
"isTouchingWater": false,
|
||||
"condition": "!q.riding_alt_pose('SPRINTING')",
|
||||
"animations": [
|
||||
"q.look('head_ai')",
|
||||
"q.bedrock('mudsdale', 'ground_walk')"
|
||||
],
|
||||
"quirks": ["q.bedrock_quirk('mudsdale', 'blink')"]
|
||||
},
|
||||
"running": {
|
||||
"poseTypes": ["WALK"],
|
||||
"isTouchingWater": false,
|
||||
"condition": "q.riding_alt_pose('SPRINTING')",
|
||||
"animations": [
|
||||
"q.look('head_ai')",
|
||||
"q.bedrock('mudsdale', 'ground_run')"
|
||||
],
|
||||
"quirks": ["q.bedrock_quirk('mudsdale', 'blink')"]
|
||||
},
|
||||
"sleep": {
|
||||
"poseTypes": ["SLEEP"],
|
||||
"animations": ["q.bedrock('mudsdale', 'sleep')"],
|
||||
"quirks": ["q.bedrock_quirk('mudsdale', 'blink')"],
|
||||
"namedAnimations": {
|
||||
"cry": "q.bedrock_stateful('dummy', 'cry')"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"species": "cobblemon:garchomp",
|
||||
"order": 1,
|
||||
"variations": [
|
||||
|
||||
@@ -97,12 +97,12 @@
|
||||
"party": {
|
||||
"type": "simple",
|
||||
"pokemon": [
|
||||
"spiritomb level=100 held_item=cobblemon:sitrus_berry ability=pressure nature=jolly moves=darkpulse,shadowball,willowisp,suckerpunch hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=252 special_attack_ev=252 speed_ev=6",
|
||||
"porygonz level=100 held_item=cobblemon:life_orb ability=adaptability nature=timid moves=hyperbeam,shadowball,icebeam,thunderbolt hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=6 special_attack_ev=252 speed_ev=252",
|
||||
"togekiss level=100 held_item=cobblemon:leftovers ability=serenegrace nature=timid moves=airslash,dazzlinggleam,aurasphere,thunderwave hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=6 special_attack_ev=252 speed_ev=252",
|
||||
"lucario level=100 held_item=cobblemon:focus_sash ability=innerfocus nature=jolly moves=closecombat,meteormash,earthquake,extremespeed hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=6 attack_ev=252 speed_ev=252",
|
||||
"milotic level=100 held_item=cobblemon:flame_orb ability=marvelscale nature=bold moves=recover,mirrorcoat,icebeam,scald hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=252 defence_ev=252 special_attack_ev=6",
|
||||
"garchomp level=100 held_item=cobblemon:yache_berry ability=roughskin nature=jolly moves=dragonclaw,earthquake,swordsdance,poisonjab hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=6 attack_ev=252 speed_ev=252"
|
||||
"spiritomb level=100 pokeball=master_ball held_item=cobblemon:sitrus_berry ability=pressure nature=jolly moves=darkpulse,shadowball,willowisp,suckerpunch hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=252 special_attack_ev=252 speed_ev=6",
|
||||
"porygonz level=100 pokeball=great_ball held_item=cobblemon:life_orb ability=adaptability nature=timid moves=hyperbeam,shadowball,icebeam,thunderbolt hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=6 special_attack_ev=252 speed_ev=252",
|
||||
"togekiss level=100 pokeball=ultra_ball held_item=cobblemon:leftovers ability=serenegrace nature=timid moves=airslash,dazzlinggleam,aurasphere,thunderwave hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=6 special_attack_ev=252 speed_ev=252",
|
||||
"lucario level=100 pokeball=dive_ball held_item=cobblemon:focus_sash ability=innerfocus nature=jolly moves=closecombat,meteormash,earthquake,extremespeed hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=6 attack_ev=252 speed_ev=252",
|
||||
"milotic level=100 pokeball=love_ball held_item=cobblemon:flame_orb ability=marvelscale nature=bold moves=recover,mirrorcoat,icebeam,scald hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=252 defence_ev=252 special_attack_ev=6",
|
||||
"garchomp level=100 pokeball=quick_ball held_item=cobblemon:yache_berry ability=roughskin nature=jolly moves=dragonclaw,earthquake,swordsdance,poisonjab hp_iv=31 attack_iv=31 defence_iv=31 special_attack_iv=31 special_defence_iv=31 speed_iv=31 hp_ev=6 attack_ev=252 speed_ev=252"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -317,26 +317,5 @@
|
||||
"tutor:waterpulse"
|
||||
],
|
||||
"preEvolution": "dragonair",
|
||||
"evolutions": [],
|
||||
"riding": {
|
||||
"stats": {
|
||||
"SPEED": {
|
||||
"ranges": "30-60"
|
||||
},
|
||||
"ACCELERATION": {
|
||||
"ranges": "30-65"
|
||||
},
|
||||
"SKILL": {
|
||||
"ranges": "30-60"
|
||||
},
|
||||
"JUMP": {
|
||||
"ranges": "30-60"
|
||||
},
|
||||
"STAMINA": {
|
||||
"ranges": "35-75"
|
||||
}
|
||||
},
|
||||
"seats": [],
|
||||
"controller": null
|
||||
}
|
||||
"evolutions": []
|
||||
}
|
||||
@@ -59,6 +59,64 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"riding": {
|
||||
"stats": {
|
||||
"SPEED": {
|
||||
"ranges": {
|
||||
"LAND": "100-101",
|
||||
"LIQUID": "5-20"
|
||||
}
|
||||
},
|
||||
"ACCELERATION": {
|
||||
"ranges": {
|
||||
"LAND": "100-101",
|
||||
"LIQUID": "50-80"
|
||||
}
|
||||
},
|
||||
"SKILL": {
|
||||
"ranges": {
|
||||
"LAND": "100-101",
|
||||
"LIQUID": "20-40"
|
||||
}
|
||||
},
|
||||
"JUMP": {
|
||||
"ranges": {
|
||||
"LAND": "100-101",
|
||||
"LIQUID": "5-10"
|
||||
}
|
||||
},
|
||||
"STAMINA": {
|
||||
"ranges": {
|
||||
"LAND": "100-101",
|
||||
"LIQUID": "25-65"
|
||||
}
|
||||
}
|
||||
},
|
||||
"seats": [
|
||||
{
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.4,
|
||||
"z": 0
|
||||
},
|
||||
"poseOffsets": [
|
||||
{
|
||||
"poseTypes": [
|
||||
"WALK"
|
||||
],
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.0,
|
||||
"z": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"controller": {
|
||||
"key": "cobblemon:land/generic"
|
||||
}
|
||||
},
|
||||
"drops": {
|
||||
"amount": 6,
|
||||
"entries": [
|
||||
|
||||
Reference in New Issue
Block a user