forked from mirrors/cobblemon
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0dd0a78741 |
@@ -2,7 +2,6 @@
|
||||
## [1.7.0 (Month xth, 2025)](#1-7-0)
|
||||
|
||||
### Additions
|
||||
- Added `/spectateBattle <player>` command to spectate battles without having to manually walk up to the target.
|
||||
- Added an in-game configuration screen, allowing all settings from `main.json` to be edited directly in-game.
|
||||
- Added `/cobblemonconfig reload` command to reload `main.json` configuration. **Note:** Some settings require a server restart to take effect; use this command cautiously.
|
||||
- Added `blacklisted_items_to_hold` and `whitelisted_items_to_hold` tags to allow for controlling which items players can give to their Pokémon. If the whitelist is empty, it will consider all item as allowed (unless they are in the blacklist).
|
||||
@@ -11,7 +10,6 @@
|
||||
- Added cosmetic item functionality for Pokémon. Certain cosmetic items can be given to applicable Pokémon via the interact menu.
|
||||
- Added the various log blocks as cosmetic items for Timburr and Komala.
|
||||
- Added `visibility/hidden`, `visibility/hat` and `visibility/face` tags to control where and how certain items are rendered.
|
||||
- Added `/boxcount` command to change PC boxes amount
|
||||
|
||||
### Changes
|
||||
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
|
||||
@@ -19,7 +17,6 @@
|
||||
- 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)
|
||||
@@ -74,7 +71,6 @@
|
||||
- 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)
|
||||
|
||||
|
||||
@@ -60,10 +60,8 @@ object CobblemonCommands {
|
||||
RenameBoxCommand.register(dispatcher)
|
||||
ChangeBoxWallpaperCommand.register(dispatcher)
|
||||
RunMolangScriptCommand.register(dispatcher)
|
||||
SpectateBattleCommand.register(dispatcher)
|
||||
CobblemonConfigCommand.register(dispatcher)
|
||||
UnlockPCBoxWallpaperCommand.register(dispatcher)
|
||||
ChangePCBoxesCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -71,8 +71,6 @@ 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
|
||||
@@ -788,7 +786,6 @@ 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("is_gliding") { DoubleValue(pokemonEntity.useRidingAltPose()) }
|
||||
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) }
|
||||
|
||||
+1
-5
@@ -128,12 +128,8 @@ object CobblemonPermissions {
|
||||
val RUN_MOLANG_SCRIPT = this.create("${COMMAND_PREFIX}runmolangscript", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val COBBLEMON_CONFIG_RELOAD = this.create("${COMMAND_PREFIX}cobblemonconfig.reload", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
|
||||
val CALCULATE_SEAT_POSITIONS = this.create("${COMMAND_PREFIX}calculateseatpositions", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val CHANGE_BOX_COUNT = this.create("${COMMAND_PREFIX}boxcount", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val SPECTATE_BATTLE = this.create("${COMMAND_PREFIX}spectatebattle", PermissionLevel.ALL_COMMANDS)
|
||||
|
||||
fun all(): Iterable<Permission> = this.permissions
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.adapters.RideControllerAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
import com.google.common.collect.HashBasedTable
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -212,11 +211,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
this.speciesByDex.remove(old.resourceIdentifier.namespace, old.nationalPokedexNumber)
|
||||
}
|
||||
this.speciesByDex.put(species.resourceIdentifier.namespace, species.nationalPokedexNumber, species)
|
||||
ifClient {
|
||||
if (species.implemented) {
|
||||
this.implemented.add(species)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,4 +285,4 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
return "${species.resourceIdentifier.namespace}:${species.name}"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -134,11 +134,6 @@ data class RidingManager(val entity: PokemonEntity) {
|
||||
return controller.jumpForce(entity, driver, jumpStrength)
|
||||
}
|
||||
|
||||
fun useRidingAltPose(entity: PokemonEntity, driver: Player): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.useRidingAltPose(entity, driver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to supply the delta for the lerp() between velocity
|
||||
* vectors. Called inertia for now as the way it feels when
|
||||
|
||||
-2
@@ -111,8 +111,6 @@ interface RideController : Encodable, Decodable {
|
||||
|
||||
fun useAngVelSmoothing(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun useRidingAltPose(entity: PokemonEntity, driver: Player): Boolean = false
|
||||
|
||||
//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(
|
||||
|
||||
@@ -137,12 +137,6 @@ open class PCStore(
|
||||
pcChangeObservable.emit(Unit)
|
||||
}
|
||||
|
||||
fun removeListOfBoxes(boxList: List<PCBox>,lockNewSize: Boolean = false, overflowHandler: (Pokemon) -> Unit = ::relocateEvictedBoxPokemon){
|
||||
this.lockedSize = lockNewSize
|
||||
boxes.removeAll(boxList)
|
||||
boxList.flatMap { it.asIterable() }.forEach(overflowHandler)
|
||||
pcChangeObservable.emit(Unit)
|
||||
}
|
||||
|
||||
fun tryRestoreBackedUpPokemon() {
|
||||
var newPosition = getFirstAvailablePosition()
|
||||
|
||||
+111
-87
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
@@ -23,11 +24,13 @@ import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
@@ -67,49 +70,40 @@ class DamageInstruction(
|
||||
}
|
||||
}
|
||||
}
|
||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||
val effect = privateMessage.effect()
|
||||
val source = privateMessage.battlePokemonFromOptional(battle)
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, it) }
|
||||
}
|
||||
|
||||
private fun doRecoilEvoChecks(battlePokemon: BattlePokemon) {
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (RecoilEvolutionProgress.supports(pokemon)) {
|
||||
val healthStr = privateMessage.argumentAt(1) ?: throw UnsupportedOperationException(
|
||||
"Cant get recoil string"
|
||||
)
|
||||
val newHealth =
|
||||
"([0-9]+).*".toRegex().find(healthStr)?.groups?.get(1)?.value?.toIntOrNull()
|
||||
?: throw UnsupportedOperationException("Cant get recoil string")
|
||||
val difference = pokemon.currentHealth - newHealth
|
||||
if (difference > 0) {
|
||||
val progress = pokemon.evolutionProxy.current()
|
||||
.progressFirstOrCreate({ it is RecoilEvolutionProgress }) { RecoilEvolutionProgress() }
|
||||
progress.updateProgress(RecoilEvolutionProgress.Progress(progress.currentProgress().recoil + difference))
|
||||
}
|
||||
}
|
||||
if (source != null) {
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, source)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
val effect = privateMessage.effect()
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
val publicPokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
var status = effect?.id?.let { Statuses.getStatus(it) }
|
||||
battle.dispatch {
|
||||
val pokemon = privateMessage.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
//Showdown doesnt tell us on damage if its poison or toxic so we gotta consult the entity
|
||||
if (status is PoisonStatus) {
|
||||
status = pokemon.effectedPokemon.status?.status ?: status
|
||||
val isToxic = publicPokemon.effectedPokemon.status?.status is PoisonBadlyStatus
|
||||
val realStatus = if (isToxic) PoisonBadlyStatus() else status
|
||||
// Damage effects without a action effect receive the generic damage effect
|
||||
val actionEffect = if (realStatus != null) {
|
||||
realStatus.getActionEffect()
|
||||
} else if (effect != null) {
|
||||
ActionEffects.actionEffects[cobblemonResource("generic_damage")]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
// Damage effects without a action effect receive the generic damage effect
|
||||
val actionEffect = status?.getActionEffect() ?: effect?.let {
|
||||
ActionEffects.actionEffects["generic_damage".asIdentifierDefaultingNamespace()]
|
||||
} ?: return@dispatch GO
|
||||
if (actionEffect == null) {
|
||||
return@dispatch GO
|
||||
}
|
||||
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
battlePokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
val pokemonEntity = publicPokemon.effectedPokemon.entity
|
||||
if (pokemonEntity != null) {
|
||||
providers.add(UsersProvider(pokemonEntity))
|
||||
}
|
||||
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
@@ -125,72 +119,24 @@ class DamageInstruction(
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||
val hpStatus = privateMessage.argumentAt(1)?.split(" ")?.get(0)!!
|
||||
var causedFaint = hpStatus == "0"
|
||||
val remainingHealth = hpStatus.split("/")[0].toFloat()
|
||||
val maxHealth = hpStatus.split("/").getOrNull(1)?.toFloat()
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
var causedFaint = newHealth == "0"
|
||||
val effect = privateMessage.effect()
|
||||
val source = privateMessage.battlePokemonFromOptional(battle)
|
||||
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val pokemonEntity = battlePokemon.entity
|
||||
|
||||
battle.dispatch {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val pokemonEntity = battlePokemon.entity
|
||||
//Play recoil animation if the pokemon recoiling isnt dead
|
||||
if (!causedFaint && pokemonEntity != null) {
|
||||
val pkt = PlayPosableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptyList())
|
||||
pkt.sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
y = pokemonEntity.y,
|
||||
z = pokemonEntity.z,
|
||||
worldKey = pokemonEntity.level().dimension(),
|
||||
distance = 50.0
|
||||
)
|
||||
}
|
||||
|
||||
val newHealthRatio: Float
|
||||
val remainingHealth = newHealth.split("/")[0].toInt()
|
||||
|
||||
playRecoilAnim(pokemonEntity, causedFaint)
|
||||
if (effect != null) {
|
||||
val lang = when (effect.id) {
|
||||
"blacksludge", "stickybarb", "jabocaberry", "rowapberry" -> battleLang("damage.item", pokemonName, effect.typelessData)
|
||||
"brn", "psn", "tox" -> {
|
||||
val status = Statuses.getStatus(effect.id)?.name?.path ?: return@dispatch GO
|
||||
lang("status.$status.hurt", pokemonName)
|
||||
}
|
||||
"aftermath", "innardsout" -> battleLang("damage.generic", pokemonName)
|
||||
"chloroblast", "steelbeam" -> battleLang("damage.mindblown", pokemonName)
|
||||
"jumpkick" -> battleLang("damage.highjumpkick", pokemonName)
|
||||
else -> battleLang("damage.${effect.id}", pokemonName, source?.getName() ?: Component.literal("UNKOWN"))
|
||||
}
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
sendStatusMessage(battle, effect, pokemonName, source)
|
||||
}
|
||||
|
||||
if (causedFaint) {
|
||||
newHealthRatio = 0F
|
||||
battle.dispatch {
|
||||
battlePokemon.effectedPokemon.currentHealth = 0
|
||||
battlePokemon.sendUpdate()
|
||||
GO
|
||||
}
|
||||
causedFaint = true
|
||||
} else {
|
||||
val maxHealth = newHealth.split("/")[1].toInt()
|
||||
val difference = maxHealth - remainingHealth
|
||||
newHealthRatio = remainingHealth.toFloat() / maxHealth
|
||||
battle.dispatchToFront {
|
||||
battlePokemon.effectedPokemon.currentHealth = remainingHealth
|
||||
if (difference > 0) {
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (DamageTakenEvolutionProgress.supports(pokemon)) {
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DamageTakenEvolutionProgress }) { DamageTakenEvolutionProgress() }
|
||||
progress.updateProgress(DamageTakenEvolutionProgress.Progress(progress.currentProgress().amount + difference))
|
||||
}
|
||||
}
|
||||
}
|
||||
battlePokemon.sendUpdate()
|
||||
GO
|
||||
}
|
||||
}
|
||||
privateMessage.pnxAndUuid(0)?.let { (pnx, _) -> battle.sendSidedUpdate(actor, BattleHealthChangePacket(pnx, remainingHealth.toFloat()), BattleHealthChangePacket(pnx, newHealthRatio)) }
|
||||
updateHealth(battle, battlePokemon, remainingHealth, maxHealth)
|
||||
|
||||
battle.minorBattleActions[battlePokemon.uuid] = privateMessage
|
||||
if (lastCauser is MoveInstruction) {
|
||||
@@ -215,4 +161,82 @@ class DamageInstruction(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateHealth(battle: PokemonBattle, battlePokemon: BattlePokemon, remainingHealth: Float, maxHealth: Float?) {
|
||||
val causedFaint = maxHealth == null
|
||||
val newHealthRatio = if (maxHealth == null) 0F else remainingHealth / maxHealth
|
||||
if (causedFaint) {
|
||||
battle.dispatch {
|
||||
battlePokemon.effectedPokemon.currentHealth = 0
|
||||
battlePokemon.sendUpdate()
|
||||
GO
|
||||
}
|
||||
}
|
||||
else {
|
||||
val difference = maxHealth - remainingHealth
|
||||
battle.dispatchToFront {
|
||||
battlePokemon.effectedPokemon.currentHealth = remainingHealth.toInt()
|
||||
updateDamageTakenEvo(battlePokemon, difference.toInt())
|
||||
battlePokemon.sendUpdate()
|
||||
GO
|
||||
}
|
||||
}
|
||||
privateMessage.pnxAndUuid(0)?.let { (pnx, _ ) ->
|
||||
battle.sendSidedUpdate(actor, BattleHealthChangePacket(pnx, remainingHealth), BattleHealthChangePacket(pnx, newHealthRatio))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun doRecoilEvoChecks(battlePokemon: BattlePokemon) {
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (RecoilEvolutionProgress.supports(pokemon)) {
|
||||
val healthStr = privateMessage.argumentAt(1) ?: throw UnsupportedOperationException("Cant get recoil string")
|
||||
val newHealth =
|
||||
"([0-9]+).*".toRegex().find(healthStr)?.groups?.get(1)?.value?.toIntOrNull()
|
||||
?: throw UnsupportedOperationException("Cant get recoil string")
|
||||
val difference = pokemon.currentHealth - newHealth
|
||||
if (difference > 0) {
|
||||
val progress = pokemon.evolutionProxy.current()
|
||||
.progressFirstOrCreate({ it is RecoilEvolutionProgress }) { RecoilEvolutionProgress() }
|
||||
progress.updateProgress(RecoilEvolutionProgress.Progress(progress.currentProgress().recoil + difference))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendStatusMessage(battle: PokemonBattle, effect: Effect, pokemonName: Component, source: BattlePokemon?) {
|
||||
val lang = when (effect.id) {
|
||||
"blacksludge", "stickybarb", "jabocaberry", "rowapberry" -> battleLang("damage.item", pokemonName, effect.typelessData)
|
||||
"brn", "psn", "tox" -> {
|
||||
val status = Statuses.getStatus(effect.id)?.name?.path
|
||||
lang("status.$status.hurt", pokemonName)
|
||||
}
|
||||
"aftermath", "innardsout" -> battleLang("damage.generic", pokemonName)
|
||||
"chloroblast", "steelbeam" -> battleLang("damage.mindblown", pokemonName)
|
||||
"jumpkick" -> battleLang("damage.highjumpkick", pokemonName)
|
||||
else -> battleLang("damage.${effect.id}", pokemonName, source?.getName() ?: Component.literal("UNKOWN"))
|
||||
}
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
}
|
||||
|
||||
private fun playRecoilAnim(pokemonEntity: PokemonEntity?, causedFaint: Boolean) {
|
||||
if (!causedFaint && pokemonEntity != null) {
|
||||
val pkt = PlayPosableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptyList())
|
||||
pkt.sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
y = pokemonEntity.y,
|
||||
z = pokemonEntity.z,
|
||||
worldKey = pokemonEntity.level().dimension(),
|
||||
distance = 50.0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDamageTakenEvo(battlePokemon: BattlePokemon, damageTaken: Int) {
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (DamageTakenEvolutionProgress.supports(pokemon)) {
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DamageTakenEvolutionProgress }) { DamageTakenEvolutionProgress() }
|
||||
progress.updateProgress(DamageTakenEvolutionProgress.Progress(progress.currentProgress().amount + damageTaken))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-4
@@ -18,7 +18,6 @@ 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
|
||||
|
||||
@@ -116,10 +115,9 @@ class ModelWidget(
|
||||
heldItemRenderer.renderOnModel(
|
||||
state.currentModel!!,
|
||||
heldItem?: ItemStack.EMPTY,
|
||||
state,
|
||||
state.locatorStates,
|
||||
matrices,
|
||||
context.bufferSource(),
|
||||
Vec3(0.0,-90.0,-90.0)
|
||||
context.bufferSource()
|
||||
)
|
||||
|
||||
matrices.popPose()
|
||||
|
||||
+57
-88
@@ -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.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
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: ItemRenderer = Minecraft.getInstance().itemRenderer
|
||||
private var displayContext: ItemDisplayContext = ItemDisplayContext.FIXED
|
||||
class HeldItemRenderer() {
|
||||
private val itemRenderer = Minecraft.getInstance().itemRenderer
|
||||
private var displayContext = ItemDisplayContext.FIXED
|
||||
private var scale = 1.0f
|
||||
|
||||
companion object {
|
||||
const val ITEM_FACE = "item_face"
|
||||
@@ -37,130 +37,99 @@ class HeldItemRenderer {
|
||||
}
|
||||
|
||||
fun render(
|
||||
entity: LivingEntity?,
|
||||
entity: PokemonEntity?,
|
||||
model: PosableModel,
|
||||
item: ItemStack,
|
||||
locators: Map<String, MatrixWrapper>,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int,
|
||||
seed: Int,
|
||||
rotation: Vec3
|
||||
seed: Int
|
||||
) {
|
||||
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)
|
||||
poseStack.scale(0.7f, 0.7f, 0.7f)
|
||||
poseStack.translate(0f, 0f, .28f * scale)
|
||||
poseStack.scale(0.7f * scale, 0.7f * scale, 0.7f * scale)
|
||||
}
|
||||
//item_hat locator
|
||||
(locators.containsKey(ITEM_HAT) && item.`is`(WEARABLE_HAT_ITEMS)) -> {
|
||||
(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, 0f)
|
||||
poseStack.scale(.68f, .68f, .68f)
|
||||
poseStack.mulPose(locators["item_hat"]!!.matrix)
|
||||
poseStack.translate(0f, -0.26f * scale, 0f)
|
||||
poseStack.scale(.68f * scale, .68f * scale, .68f * scale)
|
||||
}
|
||||
//item locator
|
||||
(locators.containsKey(ITEM)) -> {
|
||||
(locators.containsKey("item")) -> {
|
||||
updateModifiers("item",locators)
|
||||
poseStack.mulPose(locators["item"]!!.matrix)
|
||||
|
||||
displayContext = model.getLocatorDisplayContext(ITEM) ?: ItemDisplayContext.FIXED
|
||||
poseStack.mulPose(locators[ITEM]!!.matrix)
|
||||
applyContextTransformation(poseStack, rotation)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't render any item
|
||||
else -> {
|
||||
else -> { // Don't render any item
|
||||
poseStack.popPose()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
itemRenderer.renderStatic(entity, item, displayContext, (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND), poseStack, buffer, null, light, OverlayTexture.NO_OVERLAY, seed)
|
||||
itemRenderer.renderStatic(entity, item, displayContext, false, 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,
|
||||
state: PosableState,
|
||||
locators: Map<String, MatrixWrapper>,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
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)
|
||||
}
|
||||
light: Int = LightTexture.pack(11, 7)
|
||||
){
|
||||
if (!item.`is`(CobblemonItemTags.HIDDEN_ITEMS)) render(null, model, item, locators, poseStack, buffer, light, 0)
|
||||
}
|
||||
|
||||
fun renderOnEntity(
|
||||
entity: LivingEntity,
|
||||
item: ItemStack,
|
||||
entity: PokemonEntity,
|
||||
delegate: PokemonClientDelegate,
|
||||
model: PosableModel,
|
||||
state: PosableState,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int,
|
||||
rotation: Vec3 = Vec3(0.0,0.0,0.0)
|
||||
light: Int
|
||||
) {
|
||||
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)
|
||||
}
|
||||
val shownItem = entity.shownItem
|
||||
val locators: Map<String, MatrixWrapper> = delegate.locatorStates
|
||||
|
||||
render(entity, model, shownItem, locators, poseStack, buffer, light, 0)
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
}
|
||||
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 -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-4
@@ -37,7 +37,6 @@ 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) {
|
||||
|
||||
@@ -164,10 +163,9 @@ class PokemonOnShoulderRenderer<T : Player>(renderLayerParent: RenderLayerParent
|
||||
heldItemRenderer.renderOnModel(
|
||||
model,
|
||||
shoulderData.shownItem,
|
||||
state,
|
||||
state.locatorStates,
|
||||
matrixStack,
|
||||
buffer,
|
||||
Vec3(0.0,-90.0,-90.0)
|
||||
buffer
|
||||
)
|
||||
|
||||
model.setDefault()
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.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,7 +17,6 @@ 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
|
||||
@@ -57,7 +56,6 @@ 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
|
||||
|
||||
-26
@@ -36,18 +36,14 @@ 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.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
|
||||
|
||||
/**
|
||||
@@ -128,10 +124,6 @@ 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") {
|
||||
@@ -156,24 +148,6 @@ 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<*>) {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
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
|
||||
@@ -20,7 +19,6 @@ 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) {
|
||||
@@ -28,8 +26,6 @@ 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,
|
||||
@@ -60,20 +56,6 @@ 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)
|
||||
// }
|
||||
|
||||
+3
-5
@@ -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)/entity.scale
|
||||
shadowRadius = min((entity.boundingBox.maxX - entity.boundingBox.minX), (entity.boundingBox.maxZ) - (entity.boundingBox.minZ)).toFloat() / 1.5F * (entity.delegate as PokemonClientDelegate).entityScaleModifier
|
||||
model.posableModel = VaryingModelRepository.getPoser(entity.pokemon.species.resourceIdentifier, clientDelegate)
|
||||
model.posableModel.context = model.context
|
||||
model.setupEntityTypeContext(entity)
|
||||
@@ -160,13 +160,11 @@ class PokemonRenderer(
|
||||
//Render Held Item
|
||||
heldItemRenderer.renderOnEntity(
|
||||
entity,
|
||||
entity.shownItem,
|
||||
model.posableModel,
|
||||
clientDelegate,
|
||||
model.posableModel,
|
||||
poseMatrix,
|
||||
buffer,
|
||||
packedLight,
|
||||
Vec3(0.0,-90.0,90.0)
|
||||
packedLight
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,138 +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.command
|
||||
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCBox
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.api.text.*
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands.argument
|
||||
import net.minecraft.commands.Commands.literal
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
import net.minecraft.commands.arguments.selector.EntitySelector
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object ChangePCBoxesCommand {
|
||||
private const val NAME = "boxcount"
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
dispatcher.register(literal(NAME)
|
||||
.permission(CobblemonPermissions.CHANGE_BOX_COUNT)
|
||||
.then(literal("query").then(
|
||||
argument("player", EntityArgument.player()).executes(::executeQuery))
|
||||
)
|
||||
.then(literal("add").then(
|
||||
argument("player", EntityArgument.player()).then(
|
||||
argument("amount", IntegerArgumentType.integer(1, 1000)).executes(::executeAdd)))
|
||||
)
|
||||
.then(literal("remove").then(
|
||||
argument("player", EntityArgument.player()).then(
|
||||
argument("amount", IntegerArgumentType.integer(1, 1000)).executes(::executeRemove)))
|
||||
)
|
||||
.then(literal("set").then(
|
||||
argument("player", EntityArgument.player()).then(
|
||||
argument("amount", IntegerArgumentType.integer(1, 1000)).executes(::executeSet)))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun executeQuery(context: CommandContext<CommandSourceStack>): Int {
|
||||
val player = context.getArgument("player", EntitySelector::class.java).findSinglePlayer(context.source)
|
||||
val playerPc = player.pc()
|
||||
context.source.sendSystemMessage(lang("command.boxcount", player.name, playerPc.boxes.size))
|
||||
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
|
||||
private fun executeAdd(context: CommandContext<CommandSourceStack>): Int {
|
||||
val player = context.getArgument("player", EntitySelector::class.java).findSinglePlayer(context.source)
|
||||
val playerPc = player.pc()
|
||||
val amount = context.getArgument("amount", Int::class.java)
|
||||
|
||||
playerPc.resize(playerPc.boxes.size + amount, true)
|
||||
playerPc.sendTo(player)
|
||||
context.source.sendSystemMessage(lang("command.changeboxcount", player.name, playerPc.boxes.size).green())
|
||||
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
|
||||
private fun executeRemove(context: CommandContext<CommandSourceStack>): Int {
|
||||
val player = context.getArgument("player", EntitySelector::class.java).findSinglePlayer(context.source)
|
||||
val playerPc = player.pc()
|
||||
val amount = context.getArgument("amount", Int::class.java)
|
||||
|
||||
if (amount < playerPc.boxes.size) {
|
||||
val emptyBoxes = playerPc.boxes.filter { it.getNonEmptySlots().isEmpty() }
|
||||
|
||||
if (emptyBoxes.size >= amount) {
|
||||
remove(context,player, playerPc, amount, emptyBoxes)
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
else {
|
||||
context.source.sendSystemMessage(lang("command.changeboxcount.removing_not_empty_box").red().append("\n").append(
|
||||
lang("command.changeboxcount.force_remove").gray().onClick(true){remove(context,player, playerPc, amount, emptyBoxes)}
|
||||
))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.source.sendSystemMessage(lang("command.changeboxcount.removing_too_many_boxes", player.name, playerPc.boxes.size).red())
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
private fun executeSet(context: CommandContext<CommandSourceStack>): Int {
|
||||
val player = context.getArgument("player", EntitySelector::class.java).findSinglePlayer(context.source)
|
||||
val playerPc = player.pc()
|
||||
val amount = context.getArgument("amount", Int::class.java)
|
||||
|
||||
if (amount < playerPc.boxes.size) {
|
||||
val emptyBoxes = playerPc.boxes.filter { it.getNonEmptySlots().isEmpty() }
|
||||
val deleteAmount = playerPc.boxes.size - amount
|
||||
|
||||
if (emptyBoxes.size <= deleteAmount) {
|
||||
context.source.sendSystemMessage(lang("command.changeboxcount.removing_not_empty_box").red().append("\n").append(
|
||||
lang("command.changeboxcount.force_remove").gray().onClick(true){ remove(context,player, playerPc, deleteAmount, emptyBoxes) }
|
||||
))
|
||||
return 0
|
||||
}
|
||||
else {
|
||||
remove(context,player, playerPc, deleteAmount, emptyBoxes)
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
}
|
||||
set(context,player, playerPc, amount)
|
||||
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
|
||||
private fun set(context: CommandContext<CommandSourceStack>,player: ServerPlayer, playerPc: PCStore, amount: Int){
|
||||
playerPc.resize(amount, true)
|
||||
playerPc.sendTo(player)
|
||||
context.source.sendSystemMessage(lang("command.changeboxcount", player.name, playerPc.boxes.size).green())
|
||||
}
|
||||
|
||||
private fun remove(context: CommandContext<CommandSourceStack>,player: ServerPlayer, playerPc: PCStore, amount: Int,emptyBoxes: List<PCBox>){
|
||||
if (amount <= emptyBoxes.size) {
|
||||
playerPc.removeListOfBoxes(emptyBoxes.takeLast(amount),true)
|
||||
}
|
||||
else {
|
||||
val slicedBoxes = emptyBoxes + playerPc.boxes.takeLast(amount - emptyBoxes.size)
|
||||
playerPc.removeListOfBoxes(slicedBoxes,true)
|
||||
}
|
||||
playerPc.initialize()
|
||||
playerPc.sendTo(player)
|
||||
context.source.sendSystemMessage(lang("command.changeboxcount", player.name, playerPc.boxes.size).green())
|
||||
}
|
||||
}
|
||||
@@ -1,41 +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.command
|
||||
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands.argument
|
||||
import net.minecraft.commands.Commands.literal
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
|
||||
object SpectateBattleCommand {
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
val command = literal("spectateBattle")
|
||||
.permission(CobblemonPermissions.SPECTATE_BATTLE)
|
||||
.then(argument("player", EntityArgument.player())
|
||||
.executes(::execute))
|
||||
|
||||
dispatcher.register(command)
|
||||
}
|
||||
|
||||
private fun execute(context: CommandContext<CommandSourceStack>): Int {
|
||||
val player = context.source.playerOrException
|
||||
|
||||
val target = EntityArgument.getPlayer(context, "player")
|
||||
|
||||
SpectateBattleHandler.spectateBattle(target, player)
|
||||
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ import java.util.*
|
||||
|
||||
object CobblemonDataProvider : DataProvider {
|
||||
|
||||
// Both Forge n Fabric keep insertion order so if a registry depends on another simply register it after
|
||||
internal var canReload = true
|
||||
// Both Forge n Fabric keep insertion order so if a registry depends on another simply register it after
|
||||
private val registries = linkedSetOf<DataRegistry>()
|
||||
|
||||
@@ -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}\";",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -959,7 +959,6 @@ 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
|
||||
}
|
||||
|
||||
@@ -1311,7 +1310,7 @@ open class PokemonEntity(
|
||||
}
|
||||
} else if (form.behaviour.moving.swim.canBreatheUnderwater && !form.behaviour.moving.swim.canWalkOnWater) {
|
||||
// Use half hitbox height for swimmers
|
||||
val halfHeight = getDimensions(this.pose).height / 2.0
|
||||
val halfHeight = form.hitbox.height * form.baseScale / 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) {
|
||||
@@ -1813,11 +1812,6 @@ open class PokemonEntity(
|
||||
return this.riding.speed(this, controller)
|
||||
}
|
||||
|
||||
fun useRidingAltPose(): Boolean {
|
||||
val driver = this.controllingPassenger as? Player ?: return false
|
||||
return this.riding.useRidingAltPose(this, driver)
|
||||
}
|
||||
|
||||
var jumpInputStrength: Int = 0 // move this
|
||||
override fun onPlayerJump(strength: Int) {
|
||||
// See if this controls the hot bar element
|
||||
|
||||
+6
-29
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.net.serverhandling.battle
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
@@ -19,7 +18,9 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleInitializePacke
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.traceFirstEntityCollision
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -47,10 +48,9 @@ object SpectateBattleHandler : ServerNetworkPacketHandler<SpectateBattlePacket>
|
||||
player.sendSystemMessage(lang("ui.interact.failed").yellow())
|
||||
return
|
||||
}
|
||||
|
||||
this.spectateBattle(targetedPlayerEntity, player)
|
||||
|
||||
// Handle music
|
||||
battle.spectators.add(player.uuid)
|
||||
player.sendPacket(BattleInitializePacket(battle, null))
|
||||
player.sendPacket(BattleMessagePacket(battle.chatLog))
|
||||
target?.battleTheme?.let { player.sendPacket(BattleMusicPacket(it)) }
|
||||
}
|
||||
else {
|
||||
@@ -58,27 +58,4 @@ object SpectateBattleHandler : ServerNetworkPacketHandler<SpectateBattlePacket>
|
||||
}
|
||||
}
|
||||
|
||||
fun spectateBattle(target: ServerPlayer, player: ServerPlayer) {
|
||||
if (player == target) {
|
||||
player.sendSystemMessage(lang("command.spectatebattle.self_spectate_disallowed").red())
|
||||
return
|
||||
}
|
||||
|
||||
if (!target.isInBattle()) {
|
||||
player.sendSystemMessage(lang("command.spectatebattle.player_not_in_battle").red())
|
||||
return
|
||||
}
|
||||
|
||||
if (player.isInBattle()) {
|
||||
player.sendSystemMessage(lang("command.spectatebattle.while_battling_disallowed").red())
|
||||
return
|
||||
}
|
||||
|
||||
val battle = BattleRegistry.getBattleByParticipatingPlayer(target) ?: return
|
||||
|
||||
battle.spectators.add(player.uuid)
|
||||
player.sendPacket(BattleInitializePacket(battle, null))
|
||||
player.sendPacket(BattleMessagePacket(battle.chatLog))
|
||||
}
|
||||
|
||||
}
|
||||
+112
-243
@@ -9,7 +9,7 @@
|
||||
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.Cobblemon
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
@@ -19,9 +19,7 @@ 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.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -34,37 +32,81 @@ 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.5 })
|
||||
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
|
||||
})
|
||||
*/
|
||||
|
||||
override val condition: (PokemonEntity) -> Boolean = { true }
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression()
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
var topSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression()
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
var glideTopSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.0, 1.0)".asExpression()
|
||||
var horizontalAcceleration: Expression = "0.1".asExpression()
|
||||
private set
|
||||
// Max accel is a whole 1.0 in 3 seconds. 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 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression()
|
||||
private set
|
||||
//Seconds self propelled flight (glide is not self propelled in this case)
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression()
|
||||
private set
|
||||
//max y level for the ride
|
||||
var altitudeExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
var verticalAcceleration: Expression = "0.1".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
// 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 infiniteAltitude: Expression = "false".asExpression()
|
||||
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 speed(entity: PokemonEntity, driver: Player): Float {
|
||||
|
||||
//Retrieve the current bird controller state and stats
|
||||
//Retrieve the current bird controller state
|
||||
//val state = entity.riding.getState(KEY) { e -> BirdAirControllerState(e) }
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
return state.rideVel.length().toFloat()
|
||||
//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()
|
||||
}
|
||||
|
||||
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
@@ -76,60 +118,62 @@ 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())) * state.rideVel.z
|
||||
forwardForce += cos(Math.toRadians(rollable.pitch.toDouble())) * state.rideVel.z
|
||||
upForce = -1.0 * sin(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
|
||||
forwardForce = cos(Math.toRadians(rollable.pitch.toDouble()))
|
||||
}
|
||||
|
||||
//TODO: Add in an upwards and downwards force when pressing space maybe?
|
||||
|
||||
//Bring the ride out of the sky when stamina is depleted.
|
||||
if (state.stamina <= 0.0) {
|
||||
upForce -= 0.3
|
||||
//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)
|
||||
}
|
||||
*/
|
||||
//Retrieve the current composite controller state
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
val altitudeLimit = getRuntime(entity).resolveDouble(altitudeExpr)
|
||||
val velocity = Vec3(0.0 , upForce * state.currSpeed, forwardForce * state.currSpeed)
|
||||
|
||||
//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 topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val rotationChangeRate = 10.0
|
||||
|
||||
if (rollable != null) {
|
||||
var yawForce = rotationChangeRate * sin(Math.toRadians(rollable.roll.toDouble()))
|
||||
//for a bit of correction on the rolls influence pitch as well
|
||||
var pitchForce = -0.35 * rotationChangeRate * abs(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())))
|
||||
|
||||
//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)
|
||||
}
|
||||
|
||||
@@ -147,56 +191,42 @@ class BirdAirController : RideController {
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is Rollable) return Vec3.ZERO
|
||||
|
||||
val rollable = driver as Rollable
|
||||
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
val handling = getRuntime(entity).resolveDouble(handlingExpr)
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
|
||||
//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);
|
||||
var 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 rolling based on healing
|
||||
val rotLimit = handling
|
||||
|
||||
//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()) {
|
||||
if (abs(rollable.roll + xInput) < rotLimit) {
|
||||
if (sign(xInput) == sign(rollable.roll).toDouble()) {
|
||||
val d = abs(abs(rollable.roll) - rotLimit)
|
||||
rollForce *= (d.pow(2)) / (rotLimit.pow(2))
|
||||
xInput *= (d.pow(2)) / (rotLimit.pow(2))
|
||||
}
|
||||
} else if (sign(rollForce) == sign(rollable.roll).toDouble()) {
|
||||
rollForce = 0.0
|
||||
} else if (sign(xInput) == sign(rollable.roll).toDouble()) {
|
||||
xInput = 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)
|
||||
return Vec3(0.0, YInput, xInput)
|
||||
}
|
||||
|
||||
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, ::BirdAirState)
|
||||
|
||||
return (state.stamina / 1.0f)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
@@ -213,190 +243,29 @@ class BirdAirController : RideController {
|
||||
|
||||
override fun shouldRoll(entity: PokemonEntity) = true
|
||||
|
||||
override fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val glideTopSpeed = getRuntime(entity).resolveDouble(glideTopSpeedExpr)
|
||||
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 useRidingAltPose(entity: PokemonEntity, driver: Player): Boolean {
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
return state.gliding
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeExpression(topSpeedExpr)
|
||||
buffer.writeExpression(glideTopSpeedExpr)
|
||||
buffer.writeExpression(accelExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(altitudeExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
buffer.writeString(gravity.toString())
|
||||
buffer.writeString(horizontalAcceleration.toString())
|
||||
buffer.writeString(verticalAcceleration.toString())
|
||||
buffer.writeString(topSpeedExpr.toString())
|
||||
buffer.writeString(accelExpr.toString())
|
||||
buffer.writeString(handlingExpr.toString())
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
topSpeedExpr = buffer.readExpression()
|
||||
glideTopSpeedExpr = buffer.readExpression()
|
||||
accelExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
altitudeExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
gravity = buffer.readString().asExpression()
|
||||
horizontalAcceleration = buffer.readString().asExpression()
|
||||
verticalAcceleration = buffer.readString().asExpression()
|
||||
topSpeedExpr = buffer.readString().asExpression()
|
||||
accelExpr = buffer.readString().asExpression()
|
||||
handlingExpr = 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 = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val glideTopSpeed = getRuntime(entity).resolveDouble(glideTopSpeedExpr)
|
||||
val accel = getRuntime(entity).resolveDouble(accelExpr)
|
||||
val staminaStat = getRuntime(entity).resolveDouble(staminaExpr)
|
||||
|
||||
var glideSpeedChange = 0.0
|
||||
|
||||
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
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
lerp( state.rideVel.z,0.0, topSpeed / ( 20.0 * 30.0)))
|
||||
}
|
||||
}
|
||||
+13
-6
@@ -16,7 +16,14 @@ 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.*
|
||||
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.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -65,16 +72,16 @@ class GliderAirController : RideController {
|
||||
override fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int) = Vec3.ZERO
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeExpression(glideSpeed)
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeString(glideSpeed.toString())
|
||||
buffer.writeString(speed.toString())
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
glideSpeed = buffer.readExpression()
|
||||
speed = buffer.readExpression()
|
||||
glideSpeed = buffer.readString().asExpression()
|
||||
speed = buffer.readString().asExpression()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val KEY: ResourceLocation = cobblemonResource("air/glider")
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -198,17 +198,17 @@ class HelicopterAirController : RideController {
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(horizontalAcceleration)
|
||||
buffer.writeExpression(verticalVelocity)
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeString(gravity.toString())
|
||||
buffer.writeString(horizontalAcceleration.toString())
|
||||
buffer.writeString(verticalVelocity.toString())
|
||||
buffer.writeString(speed.toString())
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
gravity = buffer.readExpression()
|
||||
horizontalAcceleration = buffer.readExpression()
|
||||
verticalVelocity = buffer.readExpression()
|
||||
speed = buffer.readExpression()
|
||||
gravity = buffer.readString().asExpression()
|
||||
horizontalAcceleration = buffer.readString().asExpression()
|
||||
verticalVelocity = buffer.readString().asExpression()
|
||||
speed = buffer.readString().asExpression()
|
||||
}
|
||||
|
||||
|
||||
|
||||
+29
-27
@@ -49,9 +49,9 @@ class JetAirController : RideController {
|
||||
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('STAMINA', 'AIR', 60.0, 10.0)".asExpression()
|
||||
var staminaExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 60.0, 10.0)".asExpression()
|
||||
private set
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 300.0, 128.0)".asExpression()
|
||||
var jumpExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 300.0, 128.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Make configurable by json
|
||||
@@ -123,12 +123,14 @@ class JetAirController : RideController {
|
||||
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)
|
||||
|
||||
//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
|
||||
}
|
||||
|
||||
//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
|
||||
|
||||
val velocity = Vec3(0.0 , upForce, forwardForce )
|
||||
|
||||
@@ -254,29 +256,29 @@ class JetAirController : RideController {
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(minSpeed)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(handlingYawExpr)
|
||||
buffer.writeExpression(topSpeedExpr)
|
||||
buffer.writeExpression(accelExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
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())
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
gravity = buffer.readExpression()
|
||||
minSpeed = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
handlingYawExpr = buffer.readExpression()
|
||||
topSpeedExpr = buffer.readExpression()
|
||||
accelExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
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()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
+15
-40
@@ -23,7 +23,6 @@ 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
|
||||
@@ -72,37 +71,15 @@ class RunUpToFlightCompositeController : RideController {
|
||||
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
|
||||
groundState.rideVel = flightState.rideVel
|
||||
groundState.stamina = flightState.stamina
|
||||
|
||||
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.currSpeed = groundState.currSpeed
|
||||
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
|
||||
}
|
||||
getState(entity, ::RunUpToFlightCompositeState).activeController = landController
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
|
||||
}
|
||||
|
||||
return getActiveController(entity).speed(entity, driver)
|
||||
@@ -124,14 +101,6 @@ 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)
|
||||
}
|
||||
@@ -142,9 +111,19 @@ class RunUpToFlightCompositeController : RideController {
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
val controller = getActiveController(entity)
|
||||
val state = getState(entity, ::CompositeState)
|
||||
val isJumping = Minecraft.getInstance().options.keyJump.isDown
|
||||
if (controller == landController && jumpStrength >= getRuntime(entity).resolveInt(minimumJump)) {
|
||||
|
||||
//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)
|
||||
}
|
||||
|
||||
@@ -160,10 +139,6 @@ class RunUpToFlightCompositeController : RideController {
|
||||
|
||||
override fun useAngVelSmoothing(entity: PokemonEntity): Boolean = getActiveController(entity).useAngVelSmoothing(entity)
|
||||
|
||||
override fun useRidingAltPose(entity: PokemonEntity, driver: Player): Boolean {
|
||||
return getActiveController(entity).useRidingAltPose(entity, driver)
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY
|
||||
(entity: PokemonEntity,
|
||||
driver: Player,
|
||||
|
||||
-2
@@ -84,7 +84,6 @@ 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
|
||||
@@ -109,7 +108,6 @@ 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
|
||||
|
||||
+1
-3
@@ -14,7 +14,5 @@ import net.minecraft.world.phys.Vec3
|
||||
|
||||
data class BirdAirState(val entity: PokemonEntity) : RidingState {
|
||||
var currSpeed: Double = 0.0
|
||||
var stamina: Float = 1.0f
|
||||
var rideVel: Vec3 = Vec3.ZERO
|
||||
var gliding: Boolean = false
|
||||
var lastVelocity: Vec3 = Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.util
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyPosition
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCPosition
|
||||
import com.cobblemon.mod.common.net.IntSize
|
||||
@@ -96,14 +95,6 @@ fun ByteBuf.readString(): String {
|
||||
return Utf8String.read(this, 32767)
|
||||
}
|
||||
|
||||
fun ByteBuf.writeExpression(expression: Expression): ByteBuf {
|
||||
return this.writeString(expression.getString())
|
||||
}
|
||||
|
||||
fun ByteBuf.readExpression(): Expression {
|
||||
return this.readString().asExpression()
|
||||
}
|
||||
|
||||
fun <T> ByteBuf.readNullable(reader: (ByteBuf) -> T): T? {
|
||||
val isPresent = this.readBoolean()
|
||||
if (isPresent) {
|
||||
|
||||
+101
-278
@@ -124,14 +124,8 @@
|
||||
},
|
||||
"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]
|
||||
}
|
||||
},
|
||||
@@ -562,6 +556,105 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
@@ -903,276 +996,6 @@
|
||||
"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,14 +81,6 @@
|
||||
{"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",
|
||||
@@ -107,14 +99,6 @@
|
||||
{"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,14 +97,6 @@
|
||||
{"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",
|
||||
@@ -114,14 +106,6 @@
|
||||
{"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,14 +81,6 @@
|
||||
{"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",
|
||||
@@ -107,14 +99,6 @@
|
||||
{"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,18 +79,29 @@
|
||||
"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": "item_right",
|
||||
"parent": "arm_right",
|
||||
"pivot": [-6, 12, -2],
|
||||
"locators": {
|
||||
"item_right": [-6, 12, -2]
|
||||
}
|
||||
"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": "arm_left",
|
||||
@@ -101,14 +112,6 @@
|
||||
{"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,16 +3,11 @@
|
||||
"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', 'return', q.curve('symmetrical_wide'), q.exclude_labels('look'))",
|
||||
"recall": "q.bedrock_primary('trainer_generic', 'send_out', 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": {
|
||||
|
||||
+113
-146
@@ -20,7 +20,7 @@
|
||||
"parent": "charizard",
|
||||
"pivot": [0, 0, -1],
|
||||
"locators": {
|
||||
"root": [0, 0, 0]
|
||||
"root": [0, 0, -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -28,7 +28,7 @@
|
||||
"parent": "charizard",
|
||||
"pivot": [0, 41, -1],
|
||||
"locators": {
|
||||
"top": [0, 41, 0]
|
||||
"top": [0, 41, -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -116,7 +116,8 @@
|
||||
{
|
||||
"name": "head_correction",
|
||||
"parent": "head",
|
||||
"pivot": [0, 43.5, -0.5]
|
||||
"pivot": [0, 43.5, -0.5],
|
||||
"rotation": [-95, 0, 0]
|
||||
},
|
||||
{
|
||||
"name": "head_ai",
|
||||
@@ -127,20 +128,15 @@
|
||||
"name": "head_angle",
|
||||
"parent": "head_ai",
|
||||
"pivot": [0, 43.5, -0.5],
|
||||
"rotation": [95, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 41.5, -2], "size": [7, 7, 5], "uv": [48, 0]},
|
||||
{"origin": [-3.5, 41.5, -4], "size": [7, 4, 2], "uv": [95, 64]}
|
||||
{"origin": [-3.5, 41.5, -4], "size": [7, 4, 2], "uv": [95, 64]},
|
||||
{"origin": [-2.5, 48, -2], "size": [5, 5, 2], "inflate": 0.02, "uv": [37, 31]},
|
||||
{"origin": [-2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [-2, 52.51777, -2], "rotation": [45, 0, 15], "uv": [43, 42]},
|
||||
{"origin": [2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [2, 52.51777, -2], "rotation": [45, 0, -15], "uv": [41, 42]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "item_hat",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 45, 3],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"item_hat": [0, 45, 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_head",
|
||||
"parent": "head_angle",
|
||||
@@ -150,51 +146,59 @@
|
||||
"head": [0, 46.5, 3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_face",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 53.75, -0.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"face": [0, 53.75, -0.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_item_face",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 48.5, 0.5],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"item_face": [0, 48.5, 0.5]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_mouth",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 45.75, -2],
|
||||
"pivot": [0, 48.75, -3],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"mouth": [0, 45.75, -2],
|
||||
"special": [0, 45.75, -2]
|
||||
"mouth": [0, 48.75, -3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eyes",
|
||||
"name": "locator_special_attack",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, -3.5, 1.5]
|
||||
"pivot": [0, 48.75, -3],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"special_attack": [0, 48.75, -3]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 51.75, -2.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"jaw1": [0, 51.75, -2.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "brow",
|
||||
"parent": "eyes",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 48.275, 1.765],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 48.55, 1], "size": [5, 0, 1], "uv": [0, 14]},
|
||||
{"origin": [-3.5, 47.5, 1.53], "size": [7, 1, 1], "inflate": 0.04, "uv": [0, 12]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, -3.5, 1.5]
|
||||
},
|
||||
{
|
||||
"name": "locator_face",
|
||||
"parent": "eye",
|
||||
"pivot": [0, 53.75, -0.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"face": [0, 53.75, -0.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eye_right",
|
||||
"parent": "eyes",
|
||||
"parent": "eye",
|
||||
"pivot": [-2.75, 47.75, 0.875],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 47.5, 0], "size": [2, 1, 2], "inflate": 0.01, "uv": [106, 36]},
|
||||
@@ -222,7 +226,7 @@
|
||||
},
|
||||
{
|
||||
"name": "eye_left",
|
||||
"parent": "eyes",
|
||||
"parent": "eye",
|
||||
"pivot": [2.75, 47.75, 0.875],
|
||||
"cubes": [
|
||||
{"origin": [1.5, 47.5, 0], "size": [2, 1, 2], "inflate": 0.01, "uv": [44, 82]},
|
||||
@@ -251,91 +255,6 @@
|
||||
{"origin": [2.41, 46.4, 0.5], "size": [1, 1, 1], "inflate": 0.03, "uv": [39, 86]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "muzzle",
|
||||
"parent": "head_angle",
|
||||
"pivot": [-3, 48.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 48, -2], "size": [5, 5, 2], "inflate": 0.02, "uv": [37, 31]},
|
||||
{"origin": [-2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [-2, 52.51777, -2], "rotation": [45, 0, 15], "uv": [43, 42]},
|
||||
{"origin": [2, 51.48744, -3.03033], "size": [0, 1, 1], "inflate": 0.01, "pivot": [2, 52.51777, -2], "rotation": [45, 0, -15], "uv": [41, 42]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_upper",
|
||||
"parent": "muzzle",
|
||||
"pivot": [0, 51.75, -2.25],
|
||||
"rotation": [-90, 0, 0],
|
||||
"locators": {
|
||||
"jaw1": [0, 51.75, -2.25]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nose",
|
||||
"parent": "muzzle",
|
||||
"pivot": [0, 53, 0],
|
||||
"rotation": [-40, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 51.36698, -1.67861], "size": [5, 2, 2], "inflate": 0.03, "uv": [48, 12]},
|
||||
{"origin": [-2, 53.40698, -1.17861], "size": [4, 0, 1], "uv": [0, 15]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 45.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 45.5, -4], "size": [7, 3, 2], "inflate": 0.01, "uv": [76, 20]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw2",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 48.5, -4],
|
||||
"rotation": [-7.5, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, 48.49, -4], "size": [4, 4, 2], "uv": [0, 51]},
|
||||
{"origin": [-1.5, 48.5, -2], "size": [3, 4, 0], "uv": [90, 0]},
|
||||
{"origin": [1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [1.5, 52.52782, -2], "rotation": [45, 0, -7.5], "uv": [37, 39]},
|
||||
{"origin": [-1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [-1.5, 52.52782, -2], "rotation": [45, 0, 7.5], "uv": [37, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw2",
|
||||
"pivot": [0, 51.75, -1.75],
|
||||
"locators": {
|
||||
"jaw2": {
|
||||
"offset": [0, 51.75, -1.75],
|
||||
"rotation": [-90, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tongue",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 45.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, 45.5, -2], "size": [3, 3, 0], "uv": [87, 29]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tongue2",
|
||||
"parent": "tongue",
|
||||
"pivot": [0, 48.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1, 48.5, -2], "size": [2, 2, 0], "inflate": 0.01, "uv": [46, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tongue3",
|
||||
"parent": "tongue2",
|
||||
"pivot": [0, 50.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1, 50.5, -2], "size": [2, 1, 0], "uv": [37, 43]},
|
||||
{"origin": [-0.5, 51.5, -2], "size": [1, 1, 0], "uv": [45, 43]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "horns",
|
||||
"parent": "head_angle",
|
||||
@@ -381,6 +300,72 @@
|
||||
"horn2": [2.5, 39, 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nose",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 53, 0],
|
||||
"rotation": [-40, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2.5, 51.36698, -1.67861], "size": [5, 2, 2], "inflate": 0.03, "uv": [48, 12]},
|
||||
{"origin": [-2, 53.40698, -1.17861], "size": [4, 0, 1], "uv": [0, 15]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw",
|
||||
"parent": "head_angle",
|
||||
"pivot": [0, 45.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 45.5, -4], "size": [7, 3, 2], "inflate": 0.01, "uv": [76, 20]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "jaw2",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 48.5, -4],
|
||||
"rotation": [-7.5, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, 48.49, -4], "size": [4, 4, 2], "uv": [0, 51]},
|
||||
{"origin": [-1.5, 48.5, -1.99], "size": [3, 4, 0], "uv": [90, 0]},
|
||||
{"origin": [1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [1.5, 52.52782, -2], "rotation": [45, 0, -7.5], "uv": [37, 39]},
|
||||
{"origin": [-1.5, 51.49749, -3.03033], "size": [0, 1, 1], "pivot": [-1.5, 52.52782, -2], "rotation": [45, 0, 7.5], "uv": [37, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_jaw_lower",
|
||||
"parent": "jaw2",
|
||||
"pivot": [0, 51.75, -1.75],
|
||||
"locators": {
|
||||
"jaw2": {
|
||||
"offset": [0, 51.75, -1.75],
|
||||
"rotation": [-90, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tongue",
|
||||
"parent": "jaw",
|
||||
"pivot": [0, 45.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, 45.5, -2], "size": [3, 3, 0], "uv": [87, 29]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tongue2",
|
||||
"parent": "tongue",
|
||||
"pivot": [0, 48.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1, 48.5, -2], "size": [2, 2, 0], "inflate": 0.01, "uv": [46, 38]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tongue3",
|
||||
"parent": "tongue2",
|
||||
"pivot": [0, 50.5, -2],
|
||||
"cubes": [
|
||||
{"origin": [-1, 50.5, -2], "size": [2, 1, 0], "uv": [37, 43]},
|
||||
{"origin": [-0.5, 51.5, -2], "size": [1, 1, 0], "uv": [45, 43]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arms",
|
||||
"parent": "torso2",
|
||||
@@ -418,14 +403,6 @@
|
||||
{"origin": [-21.5, 22, -1.5], "size": [3, 2, 3], "inflate": 0.1, "uv": [0, 58]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_item",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-21.6, 23, 0],
|
||||
"locators": {
|
||||
"item": [-21.6, 23, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "locator_hand_primary",
|
||||
"parent": "hand_right",
|
||||
@@ -936,14 +913,6 @@
|
||||
{"origin": [0, 9.5, 58.5], "size": [0, 13, 7], "pivot": [0, 14.45, 62], "rotation": [0, 90, 0], "uv": [0, 92]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_fire",
|
||||
"parent": "fire2",
|
||||
"pivot": [0, 11, 62],
|
||||
"locators": {
|
||||
"fire": [0, 11, 62]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "legs",
|
||||
"parent": "body",
|
||||
@@ -976,10 +945,9 @@
|
||||
{
|
||||
"name": "locator_foot_primary",
|
||||
"parent": "foot_right",
|
||||
"pivot": [-9, 1.5, -5],
|
||||
"rotation": [90, 0, 0],
|
||||
"pivot": [-9, 1.5, -7],
|
||||
"locators": {
|
||||
"foot_primary": [-9, 1.5, -5]
|
||||
"foot_primary": [-9, 1.5, -7]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1041,10 +1009,9 @@
|
||||
{
|
||||
"name": "locator_foot_secondary",
|
||||
"parent": "foot_left",
|
||||
"pivot": [9, 1.5, -5],
|
||||
"rotation": [90, 0, 0],
|
||||
"pivot": [9, 1.5, -7],
|
||||
"locators": {
|
||||
"foot_secondary": [9, 1.5, -5]
|
||||
"foot_secondary": [9, 1.5, -7]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
-10
@@ -86,22 +86,12 @@
|
||||
"fly": {
|
||||
"poseTypes": ["FLY"],
|
||||
"isBattle": false,
|
||||
"condition": "!q.is_gliding",
|
||||
"animations": ["q.look('head_ai')", "q.bedrock('charizard', 'air_fly')"],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('charizard', 'blink')",
|
||||
"q.bedrock_quirk('charizard', 'air_fly_quirk')"
|
||||
]
|
||||
},
|
||||
"glide": {
|
||||
"poseTypes": ["FLY"],
|
||||
"isBattle": false,
|
||||
"condition": "q.is_gliding",
|
||||
"animations": ["q.look('head_ai')", "q.bedrock('charizard', 'air_glide_TEST')"],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('charizard', 'blink')"
|
||||
]
|
||||
},
|
||||
"surface_idle": {
|
||||
"poseTypes": ["STAND", "FLOAT"],
|
||||
"isTouchingWater": true,
|
||||
|
||||
@@ -1561,20 +1561,12 @@
|
||||
"cobblemon.command.pokebox.last_pokemon": "Did not send that Player's last Pokémon to the PC.",
|
||||
"cobblemon.command.pokemonrestart": "Cleared %1$s's party and PC.",
|
||||
"cobblemon.command.freezepokemon.non_pokemon": "You are not looking at a Pokémon.",
|
||||
"cobblemon.command.spectatebattle.self_spectate_disallowed": "You can't spectate yourself.",
|
||||
"cobblemon.command.spectatebattle.while_battling_disallowed": "You can't spectate other people while battling.",
|
||||
"cobblemon.command.spectatebattle.player_not_in_battle": "This player is not in a battle.",
|
||||
"cobblemon.command.npcedit.non_npc": "You are not looking at a NPC.",
|
||||
"cobblemon.command.cobblemon_config.reload": "Reloading Cobblemon settings.",
|
||||
"cobblemon.command.unlockboxwallpaper.success": "%1$s can now use the %2$s wallpaper.",
|
||||
"cobblemon.command.unlockboxwallpaper.already": "%1$s already has the %2$s wallpaper.",
|
||||
"cobblemon.wallpaper_unlocked": "Wallpaper Unlocked",
|
||||
"cobblemon.unknown_wallpaper": "???",
|
||||
"cobblemon.command.changeboxcount": "%1$s now has %2$s PC boxes",
|
||||
"cobblemon.command.changeboxcount.removing_not_empty_box": "A box you are trying to remove is not empty",
|
||||
"cobblemon.command.boxcount": "%1$s currently has %2$s PC boxes",
|
||||
"cobblemon.command.changeboxcount.removing_too_many_boxes": "You can't remove all the boxes. %1$s currently has %2$s PC boxes",
|
||||
"cobblemon.command.changeboxcount.force_remove": "Click here to remove anyway",
|
||||
|
||||
"cobblemon.config.ui.search_configurations": "Search Configurations",
|
||||
"cobblemon.config.ui.reset": "Reset",
|
||||
|
||||
@@ -97,12 +97,12 @@
|
||||
"party": {
|
||||
"type": "simple",
|
||||
"pokemon": [
|
||||
"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"
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user