Compare commits

..
1 Commits
499 changed files with 1511 additions and 9902 deletions
+21 -85
View File
@@ -1,108 +1,44 @@
# Changelog
## [1.5.1 (May 27th, 2024)](#1-5-1)
## [1.5.1](#1-5-1)
### Additions
- Added unique send out particles for Cherish, Dream, Beast, and Ancient Origin balls.
- Made Wooloo and Dubwool dye-able like sheep. So cute!
- Added stat up and down particles.
- Most status effects now have particles! These include: Paralysis, Poison, Sleep, Confusion, Infatuation.
#### Move Particle Effects
- Confusion
- Cotton Guard
- Growl
- Ice Punch
- Fire Punch
- Thunder Punch
- Minimize
- Quick Attack
- Protect
- Swords Dance
- Sand Attack
- Poison Powder
- Sleep Powder
- Stun Spore
- Powder
- Rage Powder
- Spore
- Thunder Wave
- Made Wooloo and Dubwool dye-able like sheep
### Changes
- Sounds for Relic Coin Sacks have been correctly renamed. Relic Coin Pouches received new sounds for breaking and placing.
- Readjusted Petilil portraits so they fit a bit better.
- Improved handling of Pokémon taken from the Restoration Tank block to be a bit more stable.
- Made Mulch cheaper to craft.
- Readjusted Petilil portraits
- Changed "dimensions" spawn condition to check with dimension IDs instead of effects, so custom dimension IDs can be used.
### Fixes
- Fixed a bug in which adding organic material to the restoration tank via right click was adding the full count of the stack currently in hand - but only taking 1 of the item.
- Fixed a bug in which adding organic material to the fossil tank via right click was adding the full count of the stack currently in hand
- Fixed a niche issue where some properties of entities were not initialized correctly, causing Pokémon that appeared to be level 1 until you battle them.
- Fixed Fossilized Drake being missing from the Fossils item tag.
- Fixed Gilded Chest block entity not being cleared on block break, creating spooky ghost blocks. Old ones can be fixed by placing something like a furnace where it was, then breaking the furnace.
- Fixed sherd brokenness on Forge.
- Fixed Supplementaries incompatibility.
- Fixed Fossil Compartment crash with Jade / WAILA forks.
- Fixed Gilded Chest block entity not being cleared on block break
- Fixed sherd brokenness on Forge/Supplementaries incompat
- Fixed Fossil Compartment crash with Jade / WAILA forks
- Fixed PCStore#resize not allowing PC boxes size reduction.
- Fixed pasture block PC lookups when the player is offline.
- Fixed an untranslated battle message that occurs when using a move that just ran out of PP (e.g. Fire Blast that just got spited mid-turn).
- Fixed held items being eaten even when the held item evolutions are already unlocked.
- Fixed Hisuian Decidueye not being Grass/Fighting.
- Fixed both Decidueye forms learning both Triple Arrows and Spirit Shackle.
- Fixed Pineco being unable to evolve into Shulker Forretress.
- Fixed Kabutops T-posing when underwater. It doesn't have proper swimming animations yet, though.
- Fixed Hisuian Decidueye not being Grass/Fighting
- Fixed both Decidueye forms learning both Triple Arrows and Spirit Shackle
- Fixed Pineco being unable to evolve into Shulker Forretress
- Fixed Kabutops T-posing when underwater. It still does not have proper swimming animations yet though.
- Fixed Pidgey's missing walk animation.
- Fixed Cyndaquil's hidden flames clipping if it was swimming.
- Fixed Chimecho and Chingling being unable to spawn near bells. They are meant to!
- Fixed Tyrantrum and Wailord Party Overlay models peeking through the chat box. It was kinda funny though.
- Fixed hitbox sizes for Seedot, Nuzleaf, and Shiftry.
- Fixed Budew and Lechonk sliding if they walked for too long.
- Fixed Shedinja T-posing in battle.
- Fixed recoil evolution condition not working, making things like Basculegion unobtainable.
- Fixed issue where poser debug tools didn't work on JSON posers.
- Fixed issue where gilded chests don't close when going far away.
- Fixed issue where the restoration tank's renderer was reading old data, making it appear wrong.
- Fixed issue where the lights on the restoration tank would not animate if it was facing east. Very specific.
- Fixed client crash with the fossil machine when updating block state on a chunk that is unloaded in the client. I don't understand this but the devs are sure that all of those are real words.
- Fixed Restoration Tank crash with Create upon the tank block's destruction.
- Fixed Restoration Tank over consuming items when interacting with Create blocks.
- Fixed addons that add very many moves to a learn-set causing disappearing Pokémon (visually) issues on servers.
- Fixed Hyper Cutter and Big Pecks incorrectly stating that it prevented accuracy from being lowered in battle.
- Fixed missing messages for Rough Skin and Iron Barbs in battle.
- Fixed a bug where sometimes Pokémon sendouts wouldn't create an entity, or the entity would spawn at 0 0 0 which is not a good place for a Pokémon to be. Or any of us, really.
- Fixed issue in which a locked gilded chest would animate to the open state when the client fails to open it, such as when it is locked.
- Fixed a bug where aspects of a form would not be properly reflected on form changes (eg. Normal -> Hisui).
- Fixed generic battle effect sounds not sounding the way they were intended to.
- Fixed particle effects often not having access to some specific entity functions from MoLang.
- Fixed particles sometimes lasting a single tick too long, causing (very quick) visual glitches.
- Fixed particle rotations being inverted.
- Fixed particle events not spawning at the instigating particle's location.
- Fixed a bunch of spam during world generation.
- Fixed a bug in which throwing a Poké Ball at a player owned Pokémon with the ability Illusion would reveal its true species. Hilarious meta strategy.
- Fixed root-part animations not working for JSON posed Pokémon. You didn't notice this but if we didn't fix this in this update then if you use Quick Attack a lot you'd have seen a whole lot of [this](https://cdn.discordapp.com/attachments/1076993968803434627/1242660506783715369/Minecraft__1.20.1_-_Singleplayer_2024-05-21_22-08-17.mp4?ex=66549408&is=66534288&hm=ff95ee293eb15634fd63e6546534ea279540a1c892605e8d561593ca2c5600c5&) which is damn funny but very unintended.
- Fixed recoil evo condition.
- Fixed issue where poser debug tools didnt work on JSON posers
- Fixed issue where gilded chests dont close when going far away
### Developer
- Changed SpawnAction#complete to return a nullable generic R (the spawn action result) instead of a boolean. Provides more information this way.
- Added an event that fires when a fossil is revived, with or without a player.
- Added IVS and EVS property extractors.
- Fixed PCStore#resize not allowing PC boxes size reduction.
- Changed SpawnAction#complete to return a nullable generic R (the spawn action result) instead of a boolean. More information this way.
- Added an event when a fossil is revived, with or without a player.
### Data Pack & Resource Pack Creators
- Added support for MoLang conditions for quirks and poses.
- Changed the AttackDefenceRatio requirement to StatCompare and StatEqual. There is some backwards compatibility for AttackDefenceRatio, though.
- Changed "dimensions" spawn condition to check with dimension IDs instead of effects, so custom dimension IDs can be used.
- Added parametric motion and rotation support to particle effects.
- Added entity_scale as a molang var for particles (likely only applicable to Pokemon)
- Added support for primary quirk animations using the following format:
```JSON
{
"quirks": [
"q.bedrock_primary_quirk('<pokemon>', '<animation>', <minSeconds>, <maxSeconds>, <loopTimes>, '<excludedLabels>', q.curve('<waveFunction>'))"
]
}
```
### Localization
- Updated translations for:
- Simplified and Traditional Chinese.
- Spanish.
- Changed the AttackDefenceRatio requirement to StatCompare and StatEqual.
## [1.5.0 - The Ruins and Revival Update (May 12th, 2024)](#1-5-0)
#### "You're telling me that Mojang has added archaeology to the game? Hmm... that gives me an idea."
@@ -8,16 +8,8 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
import com.cobblemon.mod.common.block.entity.PCBlockEntity
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.block.entity.FossilAnalyzerBlockEntity
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
import com.cobblemon.mod.common.block.entity.*
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.registry.Registries
@@ -36,6 +28,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.create(::PCBlockEntity, CobblemonBlocks.PC).build(null))
@JvmField
val STADIUM: BlockEntityType<StadiumBlockEntity> = this.create("stadium_terminal", BlockEntityType.Builder.create(::StadiumBlockEntity, CobblemonBlocks.STADIUM).build(null))
@JvmField
val BERRY = this.create("berry", BlockEntityType.Builder.create(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
@@ -11,22 +11,14 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.block.*
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.FossilAnalyzerBlock
import com.cobblemon.mod.common.block.MonitorBlock
import com.cobblemon.mod.common.block.RestorationTankBlock
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.TrapdoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.block.*
import net.minecraft.block.enums.Instrument
import net.minecraft.block.piston.PistonBehavior
@@ -388,6 +380,19 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
)
@JvmField
val STADIUM = create(
"stadium_terminal",
StadiumBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.strength(2F)
.nonOpaque()
)
)
@JvmField
val DISPLAY_CASE = create(
"display_case",
@@ -23,12 +23,7 @@ import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
import com.cobblemon.mod.common.item.battle.DireHitItem
import com.cobblemon.mod.common.item.battle.GuardSpecItem
import com.cobblemon.mod.common.item.battle.XStatItem
import com.cobblemon.mod.common.item.berry.FriendshipRaisingBerryItem
import com.cobblemon.mod.common.item.berry.HealingBerryItem
import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.berry.*
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
@@ -253,6 +248,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val PC = blockItem("pc", CobblemonBlocks.PC)
@JvmField
val STADIUM = blockItem("stadium_terminal", CobblemonBlocks.STADIUM)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@@ -235,7 +235,6 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(FormUpdatePacket.ID, FormUpdatePacket::decode, PokemonUpdatePacketHandler())
// Evolution start
this.createClientBound(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler())
@@ -10,7 +10,9 @@ package com.cobblemon.mod.common.api.moves.animations
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.struct.VariableStruct
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import java.util.concurrent.CompletableFuture
@@ -41,9 +43,6 @@ class ActionEffectTimeline(
// .toList copy because I'm paranoid about iterators being trying to share between identical effects playing
chainKeyframes(context, timeline.toList().iterator(), finalFuture)
finalFuture
}.exceptionallyCompose {
it.printStackTrace()
CompletableFuture.completedFuture(Unit)
}
}
@@ -56,7 +55,6 @@ class ActionEffectTimeline(
keyframe.play(context)
.thenRun { context.currentKeyframes.remove(keyframe) }
.thenApply { chainKeyframes(context, iterator, finalFuture) }
.exceptionally { finalFuture.completeExceptionally(it) }
}
}
}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.api.moves.animations.keyframes
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
@@ -39,7 +40,7 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
val effectIdentifier = try {
effect?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0.0" } ?: effect
effect?.asExpressionLike()?.resolveString(context.runtime)
} catch (e: Exception) {
effect
}?.asIdentifierDefaultingNamespace() ?: return skip()
@@ -52,9 +52,11 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
if(hand == Hand.OFF_HAND) {
return ActionResult.SUCCESS
}
val entity = world.getBlockEntity(pos) as MultiblockEntity?
if (entity?.multiblockStructure != null) {
return entity.multiblockStructure!!.onUse(state, world, pos, player, hand, hit)
if (!world.isClient) {
val entity = world.getBlockEntity(pos) as MultiblockEntity?
if (entity?.multiblockStructure != null) {
return entity.multiblockStructure!!.onUse(state, world, pos, player, hand, hit)
}
}
return super.onUse(state, world, pos, player, hand, hit)
}
@@ -47,10 +47,6 @@ fun interface PokemonPropertyExtractor {
val NICKNAME = add { pokemon, properties -> properties.nickname = pokemon.nickname }
@JvmField
val STATUS = add { pokemon, properties -> properties.status = pokemon.status?.status?.showdownName }
@JvmField
val IVS = add { pokemon, properties -> properties.ivs = pokemon.ivs }
@JvmField
val EVS = add { pokemon, properties -> properties.evs = pokemon.evs }
@JvmField
val ILLUSION = mutableListOf(SPECIES, FORM, ASPECTS, GENDER, NICKNAME, SHINY)
@@ -101,7 +101,7 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
val level = buffer.readSizedInt(IntSize.U_SHORT)
val moves = mutableListOf<MoveTemplate>()
repeat(times = buffer.readSizedInt(IntSize.U_SHORT)) {
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
Moves.getByNumericalId(buffer.readInt())?.let(moves::add)
}
levelUpMoves[level] = moves
@@ -112,7 +112,7 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
buffer.writeSizedInt(IntSize.U_BYTE, levelUpMoves.size)
for ((level, moves) in levelUpMoves) {
buffer.writeSizedInt(IntSize.U_SHORT, level)
buffer.writeSizedInt(IntSize.U_SHORT, moves.size)
buffer.writeSizedInt(IntSize.U_BYTE, moves.size)
for (move in moves) {
buffer.writeInt(move.num)
}
@@ -51,8 +51,8 @@ enum class Stats(override val identifier: Identifier, override val displayName:
/** Gets the [Stat] from the respective Showdown id. */
fun getStat(statKey: String) = when(statKey) {
"atk", "Attack" -> ATTACK // Hyper Cutter states the full stat name "Attack"
"def", "Defense" -> DEFENCE // Big Pecks states the full stat name "Defense"
"atk" -> ATTACK
"def" -> DEFENCE
"spa" -> SPECIAL_ATTACK
"spd" -> SPECIAL_DEFENCE
"spe" -> SPEED
@@ -8,9 +8,6 @@
package com.cobblemon.mod.common.api.pokemon.status
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.util.Identifier
/**
@@ -23,6 +20,4 @@ open class Status(
val showdownName: String = "",
val applyMessage: String,
val removeMessage: String
) {
fun getActionEffect() = ActionEffects.actionEffects[name]
}
)
@@ -9,29 +9,21 @@
package com.cobblemon.mod.common.api.pokemon.status
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.pokemon.status.VolatileStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.nonpersistent.ConfuseStatus
import com.cobblemon.mod.common.pokemon.status.statuses.nonpersistent.AttractStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import net.minecraft.util.Identifier
/**
* Main API point for Statuses
* Get or register Statuses
*
* NOTE: May seem weird to have so many things called volatile statuses but the package is called nonpersistent.
* Its because volatile is a reserved keyword in Java. Cant use it in a package name
*
* @author Deltric
*/
object Statuses {
private val persistentStatuses = mutableListOf<Status>()
private val volatileStatuses = mutableListOf<Status>()
private val allStatuses = mutableListOf<Status>()
val POISON = registerStatus(PoisonStatus())
@@ -40,23 +32,13 @@ object Statuses {
val SLEEP = registerStatus(SleepStatus())
val FROZEN = registerStatus(FrozenStatus())
val BURN = registerStatus(BurnStatus())
val ATTRACT = registerStatus(AttractStatus())
val CONFUSE = registerStatus(ConfuseStatus())
fun <T: Status> registerStatus(status: T) : T {
if (status is PersistentStatus) {
persistentStatuses.add(status)
}
else if (status is VolatileStatus) {
volatileStatuses.add(status)
}
allStatuses.add(status)
return status
}
fun getStatus(name: Identifier) = allStatuses.find { status -> status.name == name }
fun getStatus(showdownName: String) = allStatuses.find { it.showdownName == showdownName }
fun getPersistentStatuses() = persistentStatuses
fun getPersistentStatuses() = allStatuses.filterIsInstance<PersistentStatus>()
}
@@ -79,15 +79,15 @@ class ParticleEvent(
particleEffect?.let { effect ->
val bedrockParticleEffect = BedrockParticleEffectRepository.getEffect(effect.effect) ?: return@let
val rootMatrix = when (effect.type) {
EventParticleEffect.EventParticleType.EMITTER,// -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
EventParticleEffect.EventParticleType.EMITTER_BOUND,// -> storm.matrixWrapper
EventParticleEffect.EventParticleType.EMITTER -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.matrixWrapper
EventParticleEffect.EventParticleType.PARTICLE,
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())).let { MatrixWrapper().updatePosition(it) }
}
val sourceVelocity = when (effect.type) {
EventParticleEffect.EventParticleType.EMITTER,// -> storm.sourceVelocity().let { { it } }
EventParticleEffect.EventParticleType.EMITTER_BOUND,// -> storm.sourceVelocity
EventParticleEffect.EventParticleType.EMITTER -> storm.sourceVelocity().let { { it } }
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.sourceVelocity
EventParticleEffect.EventParticleType.PARTICLE -> { { Vec3d.ZERO } }
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getVelocityX(), it.getVelocityY(), it.getVelocityZ()) } ?: Vec3d.ZERO).let { { it } }
}
@@ -15,12 +15,10 @@ import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.codec.CodecMapped
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
import com.cobblemon.mod.common.client.particle.ParticleStorm
import com.cobblemon.mod.common.client.render.SnowstormParticle
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.math.geometry.transformDirection
import com.cobblemon.mod.common.util.resolveDouble
import com.cobblemon.mod.common.util.resolveVec3d
import com.mojang.serialization.Codec
import com.mojang.serialization.DynamicOps
import com.mojang.serialization.codecs.PrimitiveCodec
@@ -37,79 +35,20 @@ interface ParticleMotion : CodecMapped {
init {
registerSubtype(ParticleMotionType.DYNAMIC, DynamicParticleMotion::class.java, DynamicParticleMotion.CODEC)
registerSubtype(ParticleMotionType.STATIC, StaticParticleMotion::class.java, StaticParticleMotion.CODEC)
registerSubtype(ParticleMotionType.PARAMETRIC, ParametricParticleMotion::class.java, ParametricParticleMotion.CODEC)
}
}
val type: ParticleMotionType
fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d): Vec3d
fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d
fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float): Vec3d
fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d
}
enum class ParticleMotionType {
DYNAMIC,
PARAMETRIC,
PARAMETRIC, // TODO figure out how that even works
STATIC
}
class ParametricParticleMotion(
var offset: Triple<Expression, Expression, Expression> = Triple(
NumberExpression(0.0),
NumberExpression(0.0),
NumberExpression(0.0)
),
var direction: Triple<Expression, Expression, Expression> = Triple(
NumberExpression(0.0),
NumberExpression(0.0),
NumberExpression(0.0)
)
) : ParticleMotion {
companion object {
val CODEC: Codec<ParametricParticleMotion> = RecordCodecBuilder.create { instance ->
instance.group(
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
EXPRESSION_CODEC.listOf().fieldOf("offset").forGetter { listOf(it.offset.first, it.offset.second, it.offset.third) },
EXPRESSION_CODEC.listOf().fieldOf("direction").forGetter { listOf(it.direction.first, it.direction.second, it.direction.third) }
).apply(instance) { _, offset, direction -> ParametricParticleMotion(Triple(offset[0], offset[1], offset[2]), Triple(direction[0], direction[1], direction[2])) }
}
}
override val type = ParticleMotionType.PARAMETRIC
override fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d) = Vec3d.ZERO
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d {
val stormPosition = Vec3d(particle.storm.getX(), particle.storm.getY(), particle.storm.getZ())
val offset = runtime.resolveVec3d(this.offset)
val particlePosition = Vec3d(particle.getX(), particle.getY(), particle.getZ())
val desiredPosition = stormPosition.add(offset)
return desiredPosition.subtract(particlePosition)
}
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = runtime.resolveVec3d(direction).normalize()
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
override fun readFromBuffer(buffer: PacketByteBuf) {
offset = Triple(
MoLang.createParser(buffer.readString()).parseExpression(),
MoLang.createParser(buffer.readString()).parseExpression(),
MoLang.createParser(buffer.readString()).parseExpression()
)
direction = Triple(
MoLang.createParser(buffer.readString()).parseExpression(),
MoLang.createParser(buffer.readString()).parseExpression(),
MoLang.createParser(buffer.readString()).parseExpression()
)
}
override fun writeToBuffer(buffer: PacketByteBuf) {
buffer.writeString(offset.first.getString())
buffer.writeString(offset.second.getString())
buffer.writeString(offset.third.getString())
buffer.writeString(direction.first.getString())
buffer.writeString(direction.second.getString())
buffer.writeString(direction.third.getString())
}
}
class DynamicParticleMotion(
var direction: ParticleMotionDirection = InwardsMotionDirection(),
var speed: Expression = NumberExpression(0.0),
@@ -140,23 +79,14 @@ class DynamicParticleMotion(
return direction.getDirectionVector(runtime, storm, emitterPos, particlePos).normalize().multiply(runtime.resolveDouble(speed))
}
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d {
val acceleration = Vec3d(
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d {
return Vec3d(
runtime.resolveDouble(acceleration.first),
runtime.resolveDouble(acceleration.second),
runtime.resolveDouble(acceleration.third)
)
.subtract(velocity.multiply(20 * runtime.resolveDouble(drag)))
.multiply(1 / 20.0).multiply(1 / 20.0) // blocks per second per second -> blocks per tick per tick
return Vec3d(
velocity.x + acceleration.x,
velocity.y + acceleration.y,
velocity.z + acceleration.z
)
).subtract(velocity.multiply(runtime.resolveDouble(drag)))
}
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = velocity.normalize()
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
override fun readFromBuffer(buffer: PacketByteBuf) {
@@ -304,8 +234,7 @@ class StaticParticleMotion : ParticleMotion {
override val type = ParticleMotionType.STATIC
override fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d) = Vec3d.ZERO
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d) = velocity
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = velocity.normalize()
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d) = Vec3d.ZERO
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
override fun readFromBuffer(buffer: PacketByteBuf) {}
override fun writeToBuffer(buffer: PacketByteBuf) {}
@@ -32,7 +32,6 @@ interface ParticleRotation : CodecMapped {
) {
init {
registerSubtype(ParticleRotationType.DYNAMIC, DynamicParticleRotation::class.java, DynamicParticleRotation.CODEC)
registerSubtype(ParticleRotationType.PARAMETRIC, ParametricParticleRotation::class.java, ParametricParticleRotation.CODEC)
}
}
@@ -40,34 +39,7 @@ interface ParticleRotation : CodecMapped {
fun getInitialRotation(runtime: MoLangRuntime): Double
fun getInitialAngularVelocity(runtime: MoLangRuntime): Double
fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double): Double
}
class ParametricParticleRotation(var expression: Expression = NumberExpression(0.0)): ParticleRotation {
companion object {
val CODEC: Codec<ParametricParticleRotation> = RecordCodecBuilder.create { instance ->
instance.group(
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
EXPRESSION_CODEC.fieldOf("expression").forGetter { it.expression }
).apply(instance) { _, expression ->
ParametricParticleRotation(expression)
}
}
}
override val type = ParticleRotationType.PARAMETRIC
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
override fun getInitialRotation(runtime: MoLangRuntime) = runtime.resolveDouble(expression)
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = 0.0
override fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double) = runtime.resolveDouble(expression) - angle
override fun readFromBuffer(buffer: PacketByteBuf) {
expression = MoLang.createParser(buffer.readString()).parseExpression()
}
override fun writeToBuffer(buffer: PacketByteBuf) {
buffer.writeString(expression.getString())
}
fun getAngularAcceleration(runtime: MoLangRuntime, angularVelocity: Double): Double
}
class DynamicParticleRotation(
@@ -94,15 +66,15 @@ class DynamicParticleRotation(
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
override fun getInitialRotation(runtime: MoLangRuntime) = runtime.resolveDouble(startRotation)
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = runtime.resolveDouble(speed) / 20
override fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double): Double {
override fun getAngularAcceleration(runtime: MoLangRuntime, angularVelocity: Double): Double {
val acceleration = runtime.resolveDouble(acceleration)
val nextVelocity = angularVelocity * 20 + acceleration
val nextVelocity = angularVelocity + acceleration
val drag = nextVelocity * runtime.resolveDouble(drag)
return angularVelocity + (if (abs(drag) > abs(nextVelocity)) {
return if (abs(drag) > abs(nextVelocity)) {
0.0
} else {
nextVelocity - drag - angularVelocity * 20
})
nextVelocity - drag - angularVelocity
}
}
override fun readFromBuffer(buffer: PacketByteBuf) {
@@ -1,51 +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.battles.dispatch
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import net.minecraft.util.Identifier
import java.util.concurrent.CompletableFuture
/**
* An [InterpreterInstruction] that triggers an [ActionEffectTimeline]
* I think it might be better to have this as an abstract class so we can default the fields
*
* @author Apion
* @since May 19, 2024
*/
interface ActionEffectInstruction : InterpreterInstruction {
var future: CompletableFuture<*>
var holds: MutableSet<String>
//To expose via molang, so action effects can do different stuff in different instructions
//e.g. "x is confused" vs "x hit itself in confusion"
val id: Identifier
override fun invoke(battle: PokemonBattle) {
preActionEffect(battle)
val runtime = MoLangRuntime()
battle.addQueryFunctions(runtime.environment.getQueryStruct())
runtime.environment.getQueryStruct().addStandardFunctions()
addMolangQueries(runtime)
runActionEffect(battle, runtime)
postActionEffect(battle)
}
fun preActionEffect(battle: PokemonBattle)
fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime)
fun postActionEffect(battle: PokemonBattle)
fun addMolangQueries(runtime: MoLangRuntime) {
runtime.environment.getQueryStruct()
.addFunction("instruction_id") { StringValue(id.toString()) }
}
}
@@ -8,28 +8,16 @@
package com.cobblemon.mod.common.battles.interpreter.instructions
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.battles.ShowdownInterpreter
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
import com.cobblemon.mod.common.battles.dispatch.CauserInstruction
import com.cobblemon.mod.common.battles.dispatch.GO
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import java.util.concurrent.CompletableFuture
/**
* Format: |-activate|POKEMON|EFFECT
@@ -40,50 +28,19 @@ import java.util.concurrent.CompletableFuture
* @author Hunter
* @since September 25th, 2022
*/
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : ActionEffectInstruction, CauserInstruction {
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
override var holds = mutableSetOf<String>()
override val id = cobblemonResource("activate")
override fun preActionEffect(battle: PokemonBattle) {
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
override fun invoke(battle: PokemonBattle) {
val pokemon = message.battlePokemon(0, battle) ?: return
val effect = message.effectAt(1) ?: return
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
battle.dispatch{
ShowdownInterpreter.lastCauser[battle.battleId] = message
battle.minorBattleActions[pokemon.uuid] = message
GO
}
}
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
battle.dispatch {
val effect = message.effectAt(1) ?: return@dispatch GO
val status = Statuses.getStatus(effect.id)
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
val providers = mutableListOf<Any>(battle)
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
val context = ActionEffectContext(
actionEffect = actionEffect,
runtime = runtime,
providers = providers
)
this.future = actionEffect.run(context)
holds = context.holds // Reference so future things can check on this action effect's holds
future.thenApply { holds.clear() }
return@dispatch GO
}
}
override fun postActionEffect(battle: PokemonBattle) {
battle.dispatch {
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
val effect = message.effectAt(1) ?: return@dispatch GO
val pokemonName = pokemon.getName()
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKNOWN")
ShowdownInterpreter.lastCauser[battle.battleId] = message
battle.minorBattleActions[pokemon.uuid] = message
val lang = when (effect.id) {
// Includes a 3rd argument being the magnitude level as a number
"magnitude" -> battleLang("activate.magnitude", message.argumentAt(2)?.toIntOrNull() ?: 1)
@@ -102,8 +59,7 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
else -> battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
}
battle.broadcastChatMessage(lang)
//We check holds here so the chat msg + particle effect happen more concurrently, instead of sequentially
UntilDispatch { "effects" !in holds}
WaitDispatch(1F)
}
}
}
@@ -8,25 +8,14 @@
package com.cobblemon.mod.common.battles.interpreter.instructions
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.battles.ShowdownInterpreter
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
import com.cobblemon.mod.common.battles.dispatch.GO
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.util.Identifier
import java.util.concurrent.CompletableFuture
/**
* Format: |-boost|POKEMON|STAT|AMOUNT or |-unboost|POKEMON|STAT|AMOUNT
@@ -36,33 +25,9 @@ import java.util.concurrent.CompletableFuture
* @author Hiroku
* @since August 20th, 2022
*/
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): ActionEffectInstruction {
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
override var holds = mutableSetOf<String>()
override val id = cobblemonResource("boost")
override fun preActionEffect(battle: PokemonBattle) {
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): InterpreterInstruction {
}
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
battle.dispatch {
val actionEffect = if (isBoost) BOOST_EFFECT else UNBOOST_EFFECT
val providers = mutableListOf<Any>(battle)
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
val context = ActionEffectContext(
actionEffect = actionEffect,
runtime = runtime,
providers = providers
)
this.future = actionEffect.run(context)
holds = context.holds // Reference so future things can check on this action effect's holds
future.thenApply { holds.clear() }
return@dispatch GO
}
}
override fun postActionEffect(battle: PokemonBattle) {
override fun invoke(battle: PokemonBattle) {
val pokemon = message.battlePokemon(0, battle) ?: return
val statKey = message.argumentAt(1) ?: return
val stages = message.argumentAt(2)?.toInt() ?: return
@@ -70,7 +35,7 @@ class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMe
val severity = Stats.getSeverity(stages)
val rootKey = if (isBoost) "boost" else "unboost"
battle.dispatch {
battle.dispatchWaiting {
val lang = when {
message.hasOptionalArgument("zeffect") -> battleLang("$rootKey.$severity.zeffect", pokemon.getName(), stat)
else -> battleLang("$rootKey.$severity", pokemon.getName(), stat)
@@ -82,13 +47,6 @@ class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMe
// TODO: replace with context that tracks detailed information such as # of stages
repeat(stages) { pokemon.contextManager.add(context) }
battle.minorBattleActions[pokemon.uuid] = message
return@dispatch UntilDispatch { "effects" !in holds }
}
}
companion object {
val BOOST_EFFECT = ActionEffects.actionEffects[cobblemonResource("boost")]!!
val UNBOOST_EFFECT = ActionEffects.actionEffects[cobblemonResource("unboost")]!!
}
}
@@ -8,27 +8,14 @@
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.model.PokemonBattle
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
import com.cobblemon.mod.common.battles.dispatch.GO
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import net.minecraft.util.Identifier
import java.util.concurrent.CompletableFuture
/**
* Formats: |cant|POKEMON|REASON and |cant|POKEMON|REASON|MOVE
@@ -37,40 +24,12 @@ import java.util.concurrent.CompletableFuture
* @author Deltric
* @since January 22nd, 2022
*/
class CantInstruction(val message: BattleMessage): ActionEffectInstruction {
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
override var holds = mutableSetOf<String>()
override val id = cobblemonResource("cant")
override fun preActionEffect(battle: PokemonBattle) {
class CantInstruction(val message: BattleMessage): InterpreterInstruction {
}
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
battle.dispatch {
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
val effectID = message.effectAt(1)?.id ?: return@dispatch GO
val name = pokemon.getName()
val status = Statuses.getStatus(effectID)
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
val providers = mutableListOf<Any>(battle)
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
val context = ActionEffectContext(
actionEffect = actionEffect,
runtime = runtime,
providers = providers
)
this.future = actionEffect.run(context)
holds = context.holds // Reference so future things can check on this action effect's holds
future.thenApply { holds.clear() }
GO
}
}
override fun postActionEffect(battle: PokemonBattle) {
battle.dispatch {
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
val effectID = message.effectAt(1)?.id ?: return@dispatch GO
override fun invoke(battle: PokemonBattle) {
battle.dispatchWaiting {
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
val name = pokemon.getName()
// Move may be null as it's not always given
val moveName = message.moveAt(2)?.displayName ?: run { "(Unrecognized: ${message.argumentAt(2)})".text() }
@@ -79,7 +38,7 @@ class CantInstruction(val message: BattleMessage): ActionEffectInstruction {
// TODO: in the games they use a generic image because there is a popup of the ability and the sprite of the mon, it may be good to have a similar system here
"armortail", "damp", "dazzling", "queenlymajesty" -> battleLang("cant.generic", name, moveName)
"par", "slp", "frz" -> {
val status = Statuses.getStatus(effectID)?.name?.path ?: return@dispatch GO
val status = Statuses.getStatus(effectID)?.name?.path ?: return@dispatchWaiting
lang("status.$status.is", name)
}
else -> battleLang("cant.$effectID", name, moveName)
@@ -87,10 +46,6 @@ class CantInstruction(val message: BattleMessage): ActionEffectInstruction {
battle.broadcastChatMessage(lang.red())
battle.minorBattleActions[pokemon.uuid] = message
UntilDispatch { "effects" !in holds }
}
}
}
@@ -8,21 +8,15 @@
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.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.battles.ShowdownInterpreter
import com.cobblemon.mod.common.battles.ShowdownInterpreter.lastCauser
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
import com.cobblemon.mod.common.battles.dispatch.GO
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
@@ -31,13 +25,11 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePac
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.PoisonStatus
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import java.util.concurrent.CompletableFuture
import kotlin.math.roundToInt
import net.minecraft.text.Text
import net.minecraft.util.Identifier
/**
* Format: |-damage|POKEMON|HP STATUS
@@ -51,87 +43,45 @@ class DamageInstruction(
val actor: BattleActor,
val publicMessage: BattleMessage,
val privateMessage: BattleMessage
) : ActionEffectInstruction {
) : InterpreterInstruction {
var future = CompletableFuture.completedFuture(Unit)
val expectedTarget = publicMessage.battlePokemon(0, actor.battle)
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
override var holds = mutableSetOf<String>()
override val id = cobblemonResource("damage")
override fun preActionEffect(battle: PokemonBattle) {
override fun invoke(battle: PokemonBattle) {
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
val recoiling = privateMessage.optionalArgument("from")?.equals("recoil", true) == true
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
if (recoiling) {
doRecoilEvoChecks(battlePokemon)
if (lastCauser is MoveInstruction) {
battle.dispatch {
//Is the recoil hold currently used anywhere?
UntilDispatch { "recoil" !in lastCauser.holds }
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))
}
}
}
}
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))
}
}
}
}
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
val effect = privateMessage.effect()
val battlePokemon = 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 actionEffect = status?.getActionEffect() ?: return@dispatch GO
val providers = mutableListOf<Any>(battle)
battlePokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
val context = ActionEffectContext(
actionEffect = actionEffect,
runtime = runtime,
providers = providers
)
this.future = actionEffect.run(context)
holds = context.holds // Reference so future things can check on this action effect's holds
future.thenApply { holds.clear() }
return@dispatch GO
}
}
override fun postActionEffect(battle: PokemonBattle) {
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
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)
battle.dispatch {
if (lastCauser is MoveInstruction && recoiling) {
UntilDispatch { "recoil" !in lastCauser.holds }
} else {
GO
}
}
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, it) }
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 = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
pkt.sendToPlayersAround(
@@ -142,7 +92,7 @@ class DamageInstruction(
distance = 50.0
)
}
//Play hit particle
if (pokemonEntity != null) {
RunPosableMoLangPacket(pokemonEntity.id, setOf("q.particle('cobblemon:hit', 'target')")).sendToPlayersAround(
x = pokemonEntity.x,
@@ -207,9 +157,8 @@ class DamageInstruction(
} else if (causedFaint) {
GO
} else {
UntilDispatch {"effects" !in holds}
WaitDispatch(1F)
}
}
}
}
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
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.molang.MoLangFunctions.addFunction
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.moves.Moves
@@ -29,7 +29,6 @@ import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgress
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.cobblemonResource
import java.util.concurrent.CompletableFuture
/**
@@ -122,7 +121,6 @@ class MoveInstruction(
}
runtime.environment.getQueryStruct().addFunction("move") { move.struct }
runtime.environment.getQueryStruct().addFunction("instruction_id") { StringValue(cobblemonResource("move").toString()) }
this.future = actionEffect.run(context)
holds = context.holds // Reference so future things can check on this action effect's holds
@@ -19,7 +19,6 @@ import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.SidedInventory
import net.minecraft.inventory.SimpleInventory
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.server.world.ServerWorld
@@ -210,8 +209,9 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
): SidedInventory {
val tankEntity =
(if (state.get(PART) == TankPart.TOP) world.getBlockEntity(pos.down())
else world.getBlockEntity(pos))
return if(tankEntity != null && tankEntity is RestorationTankBlockEntity) tankEntity.inv else DummyInventory()
else world.getBlockEntity(pos)) as RestorationTankBlockEntity
return tankEntity.inv
}
enum class TankPart(private val label: String) : StringIdentifiable {
@@ -229,18 +229,5 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
val PART = EnumProperty.of("part", TankPart::class.java)
val TRIGGERED = Properties.TRIGGERED
val ON = BooleanProperty.of("on")
class DummyInventory : SimpleInventory(0), SidedInventory {
override fun getAvailableSlots(side: Direction): IntArray {
return IntArray(0)
}
override fun canInsert(slot: Int, stack: ItemStack, dir: Direction?): Boolean {
return false
}
override fun canExtract(slot: Int, stack: ItemStack, dir: Direction): Boolean {
return false
}
}
}
}
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.block.entity.StadiumBlockEntity
import net.minecraft.block.BlockState
import net.minecraft.block.BlockWithEntity
import net.minecraft.block.entity.BlockEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class StadiumBlock(properties: Settings): BlockWithEntity(properties) {
override fun createBlockEntity(blockPos: BlockPos?, blockState: BlockState?): BlockEntity = StadiumBlockEntity(blockPos, blockState)
@Deprecated("Deprecated in Java")
override fun onUse(
blockState: BlockState,
world: World,
blockPos: BlockPos,
player: PlayerEntity,
interactionHand: Hand,
blockHitResult: BlockHitResult
): ActionResult {
if (player !is ServerPlayerEntity) return ActionResult.SUCCESS
val blockEntity = world.getBlockEntity(blockPos)
if (blockEntity !is StadiumBlockEntity) return ActionResult.SUCCESS
val message = "Stadium Pos: " + blockEntity.pos +
"\nPlayer 1 Pos: " + blockEntity.getPlayer1Pos() +
"\nPoke 1 Pos: " + blockEntity.getPoke1Pos() +
"\nPlayer 2 Pos: " + blockEntity.getPlayer2Pos() +
"\nPoke 2 Pos: " + blockEntity.getPoke2Pos()
player.sendMessage(text(message).red())
return ActionResult.SUCCESS
}
}
@@ -187,6 +187,10 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
if (!player.world.isClient) {
PiglinBrain.onGuardedBlockInteracted(player, true)
}
val state = entity.poseableState
state.currentModel?.let {
it.moveToPose(null, state, it.getPose("OPEN")!!)
}
return ActionResult.SUCCESS
}
@@ -62,6 +62,14 @@ class FossilAnalyzerBlockEntity(
}
override fun removeStack(slot: Int): ItemStack {
// if(analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
// val fossilMultiblockStructure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
// if (fossilMultiblockStructure.fossilInventory.size > slot) {
// val itemStack = fossilMultiblockStructure.fossilInventory.removeAt(slot)
// markDirty()
// return itemStack
// }
// }
return ItemStack.EMPTY
}
@@ -103,6 +111,7 @@ class FossilAnalyzerBlockEntity(
}
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
// return analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure && dir == Direction.DOWN
return false
}
}
@@ -38,14 +38,18 @@ open class FossilMultiblockEntity(
}
}
get() {
if(masterBlockPos != null && masterBlockPos != pos) {
return if (field != null) {
field
} else if (masterBlockPos != null && masterBlockPos != pos) {
val chunkPos = ChunkPos(masterBlockPos)
if (world?.chunkManager?.isChunkLoaded(chunkPos.x, chunkPos.z) == true) {
val entity: FossilMultiblockEntity? = world?.getBlockEntity(masterBlockPos) as FossilMultiblockEntity?
field = entity?.multiblockStructure
}
field
} else {
null
}
return field
}
override fun markRemoved() {
@@ -12,11 +12,13 @@ import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockStructure
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.Inventories
import net.minecraft.inventory.SidedInventory
import net.minecraft.inventory.SimpleInventory
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtList
@@ -53,9 +55,7 @@ class RestorationTankBlockEntity(
constructor(tankEntity: RestorationTankBlockEntity) : this(tankEntity, *Array(8) { ItemStack.EMPTY })
override fun getMaxCountPerStack(): Int {
return 1
}
override fun markDirty() {
super.markDirty()
@@ -64,6 +64,7 @@ class RestorationTankBlockEntity(
if(!itemStack.isEmpty) {
val struct = tankEntity.multiblockStructure as? FossilMultiblockStructure
val returnIdentifier = NaturalMaterials.getReturnItem(itemStack)
if(tankEntity.world != null) {
if(struct?.insertOrganicMaterial(itemStack, tankEntity.world!!) == true) {
removeStack(i)
@@ -71,15 +72,16 @@ class RestorationTankBlockEntity(
val returnItem = Registries.ITEM.get(returnIdentifier)
val returnStack = ItemStack(returnItem, itemStack.count)
var done = false
for(j in 1 until size()) {
if (returnStack.maxCount > 1) { // Only search for a merge if merging could be possible
for(j in 0 until size()) {
// Look for a inventory slot to merge with
val existingStack : ItemStack = getStack(j)
if (existingStack.isEmpty
|| (Registries.ITEM.getId(existingStack.item) == returnIdentifier && existingStack.count + returnStack.count < existingStack.maxCount)) {
if (Registries.ITEM.getId(existingStack.item) == returnIdentifier && existingStack.count + returnStack.count < existingStack.maxCount) {
setStack(j, ItemStack(returnItem, existingStack.count + returnStack.count))
done = true
}
}
}
if (!done) {
setStack(i, ItemStack(returnItem, itemStack.count))
}
@@ -102,7 +104,7 @@ class RestorationTankBlockEntity(
}
override fun getAvailableSlots(side: Direction?): IntArray {
return if (side == Direction.DOWN) intArrayOf(0,1,2,3,4,5,6,7) else intArrayOf(0)
return intArrayOf(0,1,2,3,4,5,6,7)
}
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
@@ -111,16 +113,16 @@ class RestorationTankBlockEntity(
val structure = tankEntity.multiblockStructure as FossilMultiblockStructure
val canUtilize = stack?.let { NaturalMaterials.isNaturalMaterial(it) } == true
&& structure.organicMaterialInside < FossilMultiblockStructure.MATERIAL_TO_START
&& !structure.hasCreatedPokemon
&& structure.createdPokemon == null
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return canUtilize
val returnStack = ItemStack(Registries.ITEM.get(returnItem), stack.count)
if(canUtilize && super.canInsert(returnStack)) {
if(returnStack == ItemStack.EMPTY && getStack(0) == ItemStack.EMPTY) {
// See if there's room for the return
if(returnStack == ItemStack.EMPTY) {
return true
}
// See if there's room for the return item
var emptyCount = 0
for(i in 1 until size()) {
for(i in 0 until size()) {
val existingStack : ItemStack = getStack(i)
if(existingStack == ItemStack.EMPTY) {
emptyCount += 1
@@ -128,8 +130,14 @@ class RestorationTankBlockEntity(
// 2 empty slots, safe to insert
return true
}
} else if(returnStack.maxCount > 1) {
if(Registries.ITEM.getId(existingStack.item) == returnItem && existingStack.count + returnStack.count < existingStack.maxCount) {
// Return item can merge with an item already in the inventory
return true
}
}
}
return false
}
}
}
@@ -0,0 +1,25 @@
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
import net.minecraft.util.math.BlockPos
class StadiumBlockEntity(blockPos: BlockPos?, blockState: BlockState?): BlockEntity(CobblemonBlockEntities.STADIUM, blockPos, blockState) {
fun getPlayer1Pos(): BlockPos? {
return pos.add(5, 0, 10)
}
fun getPlayer2Pos(): BlockPos? {
return pos.add(5, 0, -10)
}
fun getPoke1Pos(): BlockPos? {
return pos.add(5, 0, 5)
}
fun getPoke2Pos(): BlockPos? {
return pos.add(5, 0, -5)
}
}
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.block.multiblock
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.FossilRevivedEvent
import com.cobblemon.mod.common.api.fossil.Fossil
@@ -73,7 +74,7 @@ class FossilMultiblockStructure (
var organicMaterialInside = 0
private set
var hasCreatedPokemon: Boolean = false
var createdPokemon: Pokemon? = null
private set
var timeRemaining = -1
private set
@@ -103,7 +104,8 @@ class FossilMultiblockStructure (
if (player !is ServerPlayerEntity) {
return ActionResult.SUCCESS
}
if (this.hasCreatedPokemon) {
if (this.createdPokemon != null) {
if (this.fossilOwnerUUID != null && player.uuid != this.fossilOwnerUUID) {
var ownerName : String = "UNKNOWN_USER" // TODO: lang agnostic fallback
server()?.userCache?.getByUuid(this.fossilOwnerUUID)?.orElse(null)?.name?.let {
@@ -113,29 +115,25 @@ class FossilMultiblockStructure (
return ActionResult.FAIL
}
val ballType = (stack.item as PokeBallItem).pokeBall
if (!player.isCreative) {
stack?.decrement(1)
}
val pokemon = this.resultingFossil?.result?.create()
if(pokemon != null) {
pokemon.caughtBall = ballType
player.party().add(pokemon)
this.fossilState.growthState = "Taken"
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(pokemon, player))
}
this.createdPokemon!!.caughtBall = ballType
player.party().add(this.createdPokemon!!)
this.fossilState.growthState = "Taken"
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, createdPokemon!!)
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(createdPokemon!!, player))
// Turn the monitor off
val monitorState = world.getBlockState(monitorPos)
if(monitorState.contains(MonitorBlock.SCREEN) && !monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
if(!monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, MonitorBlock.MonitorScreen.OFF))
}
this.hasCreatedPokemon = false
this.createdPokemon = null
this.fossilOwnerUUID = null
this.protectionTime = -1
this.updateFossilType(world)
@@ -147,14 +145,15 @@ class FossilMultiblockStructure (
// Reclaim the last fossil from the machine if their hand is empty
if (player.getStackInHand(interactionHand).isEmpty) {
if(!this.isRunning() && !this.hasCreatedPokemon) {
if(!this.isRunning() && this.createdPokemon == null) {
if (fossilInventory.isEmpty()) {
return ActionResult.CONSUME
}
if(player is ServerPlayerEntity) {
player.setStackInHand(interactionHand, fossilInventory.last())
// remove last fossil in the fossil machine stack when grabbed out of the machine
this.fossilInventory.removeAt(fossilInventory.size - 1)
player.setStackInHand(interactionHand, fossilInventory.last())
// remove last fossil in the fossil machine stack when grabbed out of the machine
this.fossilInventory.removeAt(fossilInventory.size - 1)
if(!world.isClient) {
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_FOSSIL, SoundCategory.BLOCKS)
this.updateFossilType(world)
this.syncToClient(world)
@@ -166,17 +165,19 @@ class FossilMultiblockStructure (
// Check if the player is holding a fossil and if so insert it into the machine.
if (Fossils.isFossilIngredient(stack)) {
if (!this.isRunning() && !this.hasCreatedPokemon) {
if(!this.isRunning() && this.createdPokemon == null) {
if (fossilInventory.size > Cobblemon.config.maxInsertedFossilItems) {
return ActionResult.FAIL
}
if (player is ServerPlayerEntity) {
val copyFossilStack = stack.copyWithCount(1)
if (!player.isCreative) {
stack?.decrement(1)
}
fossilOwnerUUID = player.uuid
fossilInventory.add(copyFossilStack)
val copyFossilStack = stack.copyWithCount(1)
if (!player.isCreative) {
stack?.decrement(1)
}
fossilOwnerUUID = player.uuid
fossilInventory.add(copyFossilStack)
if(!world.isClient) {
this.updateFossilType(world)
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
this.syncToClient(world)
@@ -188,11 +189,7 @@ class FossilMultiblockStructure (
// Check if the player is holding a natural material and if so, feed it to the machine.
if (NaturalMaterials.isNaturalMaterial(stack)) {
if (player is ServerPlayerEntity
&& !this.isRunning()
&& !this.hasCreatedPokemon
&& this.organicMaterialInside < MATERIAL_TO_START
&& insertOrganicMaterial(ItemStack(stack.item, 1), world)) {
if (!this.isRunning() && this.createdPokemon == null && this.organicMaterialInside < MATERIAL_TO_START && insertOrganicMaterial(ItemStack(stack.item, 1), world)) {
this.lastInteraction = world.time
if (!player.isCreative) {
val returnItem = NaturalMaterials.getReturnItem(stack)
@@ -276,7 +273,7 @@ class FossilMultiblockStructure (
return 0
}
if(monitorPos == pos) {
if(hasCreatedPokemon) {
if(createdPokemon != null) {
return 15
}
if(!isRunning()) {
@@ -292,13 +289,13 @@ class FossilMultiblockStructure (
override fun onTriggerEvent(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: Random?) {
// instantiate the pokemon as a new entity and spawn it at the location of the machine
if(this.protectionTime <= 0) {
val wildPokemon: Pokemon = if (hasCreatedPokemon) resultingFossil?.result?.create() ?: return else return
val wildPokemon: Pokemon = this.createdPokemon ?: return
val direction = state?.get(HorizontalFacingBlock.FACING)?.opposite
if(pos != null && direction != null && world != null) {
val success = this.spawn(world, pos, direction, wildPokemon)
if(success) {
this.fossilState.growthState = "Taken"
this.hasCreatedPokemon = false
this.createdPokemon = null
this.fossilOwnerUUID = null
this.protectionTime = -1
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS)
@@ -315,9 +312,9 @@ class FossilMultiblockStructure (
val analyzerEntity = world.getBlockEntity(analyzerPos) as? MultiblockEntity
val tankBaseEntity = world.getBlockEntity(tankBasePos) as? MultiblockEntity
val tankTopEntity = world.getBlockEntity(tankBasePos.up()) as? MultiblockEntity
val tankBaseBlockState = world.getBlockState(tankBaseEntity?.pos)
val direction = tankBaseBlockState.get(HorizontalFacingBlock.FACING).opposite
val wildPokemon: Pokemon? = if(hasCreatedPokemon) resultingFossil?.result?.create() else null
val state = world.getBlockState(tankBaseEntity?.pos)
val direction = state.get(HorizontalFacingBlock.FACING).getOpposite()
val wildPokemon: Pokemon? = this.createdPokemon
monitorEntity?.multiblockStructure = null
analyzerEntity?.multiblockStructure = null
@@ -377,7 +374,7 @@ class FossilMultiblockStructure (
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_UNPROTECTED, SoundCategory.BLOCKS)
}
if (this.hasCreatedPokemon) {
if (this.createdPokemon != null) {
return
}
@@ -406,7 +403,10 @@ class FossilMultiblockStructure (
if (this.timeRemaining == 0) {
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_FINISHED, SoundCategory.BLOCKS)
fossilInventory.clear()
this.hasCreatedPokemon = true
this.resultingFossil?.let {
this.createdPokemon = it.result.create()
}
if(this.fossilOwnerUUID != null) {
protectionTime = PROTECTION_TIME
}
@@ -477,26 +477,20 @@ class FossilMultiblockStructure (
val upperTankPos = tankBasePos.up()
val analyzerState = world.getBlockState(analyzerPos)
val tankState = world.getBlockState(tankBasePos.up())
if (analyzerState.contains(FossilAnalyzerBlock.ON)) {
world.setBlockState(analyzerPos, analyzerState.with(FossilAnalyzerBlock.ON, timeRemaining >= 0))
}
if (tankState.contains(RestorationTankBlock.ON)) {
world.setBlockState(upperTankPos, tankState.with(RestorationTankBlock.ON, timeRemaining >= 0))
}
world.setBlockState(analyzerPos, analyzerState.with(FossilAnalyzerBlock.ON, timeRemaining >= 0))
world.setBlockState(upperTankPos, tankState.with(RestorationTankBlock.ON, timeRemaining >= 0))
}
fun updateProgress(world: World) {
val monitorState = world.getBlockState(monitorPos)
if (monitorState.contains(MonitorBlock.SCREEN)) {
val screenID = if (protectionTime > 0F) {
MonitorBlock.MonitorScreen.GREEN_PROGRESS_9
} else if (timeRemaining <= 0) {
MonitorBlock.MonitorScreen.OFF
} else {
getProgressScreen((TIME_TO_TAKE - timeRemaining) / TIME_PER_STAGE)
}
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, screenID))
val screenID = if(protectionTime > 0F ) {
MonitorBlock.MonitorScreen.GREEN_PROGRESS_9
} else if (timeRemaining <= 0) {
MonitorBlock.MonitorScreen.OFF
} else {
getProgressScreen((TIME_TO_TAKE - timeRemaining) / TIME_PER_STAGE)
}
val monitorState = world.getBlockState(monitorPos)
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, screenID))
}
fun getProgressScreen(progress:Int) : MonitorBlock.MonitorScreen {
@@ -611,7 +605,9 @@ class FossilMultiblockStructure (
result.putString(DataKeys.INSERTED_FOSSIL, this.resultingFossil!!.asString())
}
result.putBoolean(DataKeys.HAS_CREATED_POKEMON, hasCreatedPokemon)
if (this.createdPokemon != null) {
result.put(DataKeys.CREATED_POKEMON, createdPokemon!!.saveToNBT(NbtCompound()))
}
return result
}
@@ -660,10 +656,7 @@ class FossilMultiblockStructure (
}
if (nbt.contains(DataKeys.CREATED_POKEMON)) {
// migration of instances that saved the created pokeon in the nbt
result.hasCreatedPokemon = true
} else if (nbt.contains(DataKeys.HAS_CREATED_POKEMON)){
result.hasCreatedPokemon = nbt.getBoolean(DataKeys.HAS_CREATED_POKEMON)
result.createdPokemon = Pokemon.loadFromNBT(nbt.getCompound(DataKeys.CREATED_POKEMON))
}
result.fillLevel = result.organicMaterialInside * 8 / MATERIAL_TO_START
return result
@@ -8,25 +8,15 @@
package com.cobblemon.mod.common.client
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.*
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonClientImplementation
import com.cobblemon.mod.common.CobblemonEntities
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
import com.cobblemon.mod.common.api.text.gray
import com.cobblemon.mod.common.client.battle.ClientBattle
import com.cobblemon.mod.common.client.gui.PartyOverlay
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
import com.cobblemon.mod.common.client.render.block.BerryBlockRenderer
import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.block.*
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
@@ -34,10 +24,7 @@ import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererR
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BerryModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.BlockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokeBallModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.*
import com.cobblemon.mod.common.client.render.pokeball.PokeBallRenderer
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController
@@ -47,9 +34,6 @@ import com.cobblemon.mod.common.client.trade.ClientTrade
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asTranslated
@@ -221,7 +205,8 @@ object CobblemonClient {
CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
CobblemonBlocks.GIMMIGHOUL_CHEST,
CobblemonBlocks.DISPLAY_CASE
CobblemonBlocks.DISPLAY_CASE,
CobblemonBlocks.STADIUM
)
this.createBoatModelLayers()
@@ -15,6 +15,9 @@ import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import net.minecraft.client.MinecraftClient
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.util.math.RotationAxis.NEGATIVE_X
import net.minecraft.util.math.RotationAxis.POSITIVE_X
import net.minecraft.util.math.RotationAxis.POSITIVE_Y
object SpawnSnowstormParticleHandler : ClientNetworkPacketHandler<SpawnSnowstormParticlePacket> {
override fun handle(packet: SpawnSnowstormParticlePacket, client: MinecraftClient) {
@@ -10,20 +10,16 @@ package com.cobblemon.mod.common.client.particle
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies.species
import com.cobblemon.mod.common.api.snowstorm.BedrockParticleEffect
import com.cobblemon.mod.common.api.snowstorm.ParticleEmitterAction
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.client.render.SnowstormParticle
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.particle.SnowstormParticleEffect
import com.cobblemon.mod.common.util.math.geometry.transformDirection
import kotlin.random.Random
import net.minecraft.client.MinecraftClient
import net.minecraft.client.particle.NoRenderParticle
import net.minecraft.client.util.ParticleUtil.spawnParticle
import net.minecraft.client.world.ClientWorld
import net.minecraft.entity.Entity
import net.minecraft.util.math.Vec3d
@@ -52,22 +48,12 @@ class ParticleStorm(
.addFunction("entity_height") { DoubleValue(entity.boundingBox.yLength) }
.addFunction("entity_size") { DoubleValue(entity.boundingBox.run { if (xLength > yLength) xLength else yLength }) }
.addFunction("entity_radius") { DoubleValue(entity.boundingBox.run { if (xLength > yLength) xLength else yLength } / 2) }
.addFunction("entity_scale") {
val pokeEntity = entity as? PokemonEntity
val pokemon = pokeEntity?.pokemon
//Use form data if available, species as fall back
val baseScale = pokemon?.form?.baseScale ?: pokemon?.species?.baseScale ?: 1.0F
val pokemonScale = pokemon?.scaleModifier ?: 1.0F
val entityScale = pokeEntity?.scaleFactor ?: 1.0F
DoubleValue(baseScale * pokemonScale * entityScale)
}
// TODO replace with a generified call to if (entity is MoLangEntity) entity.applyVariables(env) or w/e
runtime.environment.setSimpleVariable("entity_width", DoubleValue(entity.boundingBox.xLength))
runtime.environment.setSimpleVariable("entity_height", DoubleValue(entity.boundingBox.yLength))
val longerDiameter = entity.boundingBox.run { if (xLength > yLength) xLength else yLength }
runtime.environment.setSimpleVariable("entity_size", DoubleValue(longerDiameter))
runtime.environment.setSimpleVariable("entity_radius", DoubleValue(longerDiameter / 2))
runtime.environment.setSimpleVariable("entity_scale", DoubleValue((entity as? PokemonEntity)?.scaleFactor ?: 1.0))
}
MinecraftClient.getInstance().particleManager.addParticle(this)
}
@@ -118,7 +118,7 @@ class SnowstormParticle(
init {
setVelocity(initialVelocity.x, initialVelocity.y, initialVelocity.z)
angle = -storm.effect.particle.rotation.getInitialRotation(storm.runtime).toFloat()
angle = storm.effect.particle.rotation.getInitialRotation(storm.runtime).toFloat()
prevAngle = angle
angularVelocity = storm.effect.particle.rotation.getInitialAngularVelocity(storm.runtime)
velocityMultiplier = 1F
@@ -256,20 +256,24 @@ class SnowstormParticle(
setParticleAgeInRuntime()
storm.effect.curves.forEach { it.apply(storm.runtime) }
storm.runtime.execute(storm.effect.particle.updateExpressions)
angularVelocity = storm.effect.particle.rotation.getAngularVelocity(storm.runtime, -angle.toDouble(), angularVelocity) / 20
angularVelocity += storm.effect.particle.rotation.getAngularAcceleration(storm.runtime, angularVelocity) / 20
if (age >= maxAge || storm.runtime.resolveBoolean(storm.effect.particle.killExpression)) {
if (age > maxAge || storm.runtime.resolveBoolean(storm.effect.particle.killExpression)) {
runExpirationEvents()
markDead()
return
} else {
val velocity = storm.effect.particle.motion.getVelocity(storm.runtime, this, Vec3d(velocityX, velocityY, velocityZ))
velocityX = velocity.x
velocityY = velocity.y
velocityZ = velocity.z
val acceleration = storm.effect.particle.motion.getAcceleration(
storm.runtime,
Vec3d(velocityX, velocityY, velocityZ).multiply(20.0) // Uses blocks per second, not blocks per tick
).multiply(1 / 20.0).multiply(1 / 20.0) // blocks per second per second -> blocks per tick per tick
velocityX += acceleration.x
velocityY += acceleration.y
velocityZ += acceleration.z
prevAngle = angle
// Subtract because Bedrock particles are counter-clockwise and Java Edition is clockwise.
angle = prevAngle - angularVelocity.toFloat()
angle = prevAngle + angularVelocity.toFloat()
}
viewDirection = storm.effect.particle.viewDirection.getDirection(
@@ -61,17 +61,17 @@ class RestorationTankRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEn
matrices.pop()
}
val fillLevel = struct.fillLevel
if (fillLevel == 0 && !struct.hasCreatedPokemon) {
if (fillLevel == 0 && struct.createdPokemon == null) {
return
}
if (struct.isRunning() or (struct.hasCreatedPokemon)) renderFetus(entity, tickDelta, matrices, vertexConsumers, light, overlay)
if (struct.isRunning() or (struct.createdPokemon != null)) renderFetus(entity, tickDelta, matrices, vertexConsumers, light, overlay)
matrices.push()
val transparentBuffer = vertexConsumers.getBuffer(RenderLayer.getTranslucent())
val fluidModel = if (struct.isRunning()) FLUID_MODELS[8]
else if (struct.hasCreatedPokemon) FLUID_MODELS[7]
else if (struct.createdPokemon != null) FLUID_MODELS[7]
else FLUID_MODELS[fillLevel.coerceAtMost(FLUID_MODELS.size - 1) - 1]
fluidModel.getQuads(entity.cachedState, null, entity.world?.random).forEach { quad ->
transparentBuffer?.quad(matrices.peek(), quad, 0.75f, 0.75f, 0.75f, light, OverlayTexture.DEFAULT_UV)
@@ -37,7 +37,7 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
it.environment.getQueryStruct().addFunctions(model.functions.functions)
}
val condition: ExpressionLike = json.singularToPluralList("condition").get("conditions")?.normalizeToArray()?.map { it.asString }?.asExpressionLike() ?: "true".asExpressionLike()
val condition: ExpressionLike = json.singularToPluralList("condition").get("condition")?.normalizeToArray()?.map { it.asString }?.asExpressionLike() ?: "true".asExpressionLike()
val poseName = json.get("poseName")?.asString ?: "pose"
val poseTypes = (json.get("poseTypes")?.asJsonArray?.map { name ->
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.client.render.models.blockbench
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.Entity
/**
* A storage of locator information for a model, attached to its [joint].
@@ -69,45 +68,20 @@ class LocatorAccess(
* Updates all of the locator states with the position at this current frame.
* This is the same logic as ModelPart uses, that's why we reuse ModelPart#rotate.
*/
fun update(matrixStack: MatrixStack, entity: Entity, scale: Float, state: MutableMap<String, MatrixWrapper>, isRoot: Boolean = false) {
fun update(matrixStack: MatrixStack, state: MutableMap<String, MatrixWrapper>) {
matrixStack.push()
joint.transform(matrixStack)
if (isRoot) {
matrixStack.push()
matrixStack.scale(-1F, -1F, 1F)
state.getOrPut("root") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
matrixStack.pop()
// Put in an approximation of the target locator. If the model has one defined,
// this will be overridden.
matrixStack.push()
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale, -entity.width * 0.6 / scale)
matrixStack.scale(-1F, -1F, 1F)
state.getOrPut("target") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
state.getOrPut("special_attack") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
matrixStack.pop()
// If we have the entity, put in a "middle" locator for center of mass
// this will be overridden.
matrixStack.push()
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale, 0.0)
matrixStack.scale(-1F, -1F, 1F)
state.getOrPut("middle") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
matrixStack.pop()
}
for ((name, locator) in locators) {
matrixStack.push()
locator.transform(matrixStack)
matrixStack.scale(-1F, -1F, 1F)
matrixStack.scale(1F, -1F, 1F)
state.getOrPut(name) { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
matrixStack.pop()
}
children.forEach {
it.update(matrixStack, entity, scale, state, isRoot = false)
it.update(matrixStack, state)
}
matrixStack.pop()
@@ -261,41 +261,6 @@ abstract class PoseableEntityModel<T : Entity>(
)
)
}
.addFunction("bedrock_primary_quirk") { params ->
val animationGroup = params.getString(0)
val animationNames = params.get<MoValue>(1)?.let { if (it is ArrayStruct) it.map.values.map { it.asString() } else listOf(it.asString()) } ?: listOf()
val minSeconds = params.getDoubleOrNull(2) ?: 8F
val maxSeconds = params.getDoubleOrNull(3) ?: 30F
val loopTimes = params.getDoubleOrNull(4)?.toInt() ?: 1
val excludedLabels = mutableSetOf<String>()
var curve: WaveFunction = { t ->
if (t < 0.1) {
t * 10
} else if (t < 0.9) {
1F
} else {
1F
}
}
for (index in 5 until params.params.size) {
val param = params.get<MoValue>(index)
if (param is ObjectValue<*>) {
curve = param.obj as WaveFunction
continue
}
val label = params.getString(index) ?: continue
excludedLabels.add(label)
}
ObjectValue(
quirk(
secondsBetweenOccurrences = minSeconds.toFloat() to maxSeconds.toFloat(),
condition = { true },
loopTimes = 1..loopTimes,
animation = { PrimaryAnimation(bedrockStateful(animationGroup, animationNames.random()), excludedLabels = excludedLabels, curve = curve) }
)
)
}
@Transient
val runtime = MoLangRuntime().setup().setupClient().also { it.environment.getQueryStruct().addFunctions(functions.functions) }
@@ -823,6 +788,7 @@ abstract class PoseableEntityModel<T : Entity>(
matrixStack.push()
matrixStack.scale(-1F, -1F, 1F)
scale = entity.pokemon.form.baseScale * entity.pokemon.scaleModifier * (entity.delegate as PokemonClientDelegate).entityScaleModifier
matrixStack.scale(scale, scale, scale)
} else if (entity is EmptyPokeBallEntity) {
matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(entity.yaw))
@@ -837,14 +803,27 @@ abstract class PoseableEntityModel<T : Entity>(
matrixStack.scale(1F, -1F, 1F)
}
matrixStack.push()
matrixStack.scale(1F, -1F, 1F)
val states = state.locatorStates
states.getOrPut("root") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
matrixStack.pop()
if (isForLivingEntityRenderer) {
// Standard living entity offset, only God knows why Mojang did this.
matrixStack.translate(0.0, -1.5, 0.0)
}
locatorAccess.update(matrixStack, entity, scale, states, isRoot = true)
// If we have the entity, put in an approximation of the target locator. If the model has one defined,
// this will be overridden.
matrixStack.push()
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale + 1.5F, -entity.width * 0.6 / scale)
matrixStack.scale(1F, -1F, 1F)
states.getOrPut("target") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
states.getOrPut("special_attack") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
matrixStack.pop()
locatorAccess.update(matrixStack, states)
}
fun ModelPart.translation(
@@ -135,7 +135,6 @@ abstract class PoseableEntityState<T : Entity> : Schedulable {
val storm = ParticleStorm(
effect = effect,
entity = entity,
matrixWrapper = matrixWrapper,
world = world,
runtime = particleRuntime,
@@ -39,7 +39,6 @@ import com.google.gson.annotations.SerializedName
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type
import java.util.function.Supplier
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
/**
@@ -50,8 +49,7 @@ import net.minecraft.util.math.Vec3d
* @author Hiroku
* @since August 7th, 2022
*/
class JsonPokemonPoseableModel(rootPart: Bone) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = (rootPart as ModelPart).children.entries.first().let { rootPart.registerChildWithAllChildren(it.key) }
class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableModel(), HeadedFrame {
companion object {
val gson = GsonBuilder()
.setPrettyPrinting()
@@ -132,7 +130,6 @@ class JsonPokemonPoseableModel(rootPart: Bone) : PokemonPoseableModel(), HeadedF
override fun createInstance(type: Type): JsonPokemonPoseableModel {
return JsonPokemonPoseableModel(modelPart!!).also {
model = it
modelPart as ModelPart
it.loadAllNamedChildren(modelPart!!)
}
}
@@ -1,62 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
class SmeargleModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BipedFrame {
override val rootPart = root.registerChildWithAllChildren("smeargle")
override val head = getPart("head")
/* No arm swinging because it's holding its tail */
override val leftLeg = getPart("leg_left")
override val rightLeg = getPart("leg_right")
override var portraitScale = 1.29F
override var portraitTranslation = Vec3d(-0.03, 0.96, 0.0)
override var profileScale = 0.67F
override var profileTranslation = Vec3d(0.05, 0.8, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
//override val cryAnimation = CryProvider { _, _ -> bedrockStateful("smeargle", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("smeargle", "blink") }
standing = registerPose(
poseName = "standing",
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES + PoseType.SLEEP,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("smeargle", "ground_idle")
)
)
walk = registerPose(
poseName = "walk",
poseTypes = PoseType.MOVING_POSES,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
singleBoneLook(),
bedrock("smeargle", "ground_idle"),
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
)
)
}
}
@@ -47,6 +47,7 @@ class ShedinjaModel (root: ModelPart) : PokemonPoseableModel() {
poseName = "standing",
poseTypes = PoseType.UI_POSES + PoseType.STAND,
transformTicks = 10,
condition = { !it.isBattling },
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("shedinja", "ground_idle")
@@ -20,7 +20,7 @@ import net.minecraft.util.math.Vec3d
class WailordModel(root: ModelPart) : PokemonPoseableModel() {
override val rootPart = root.registerChildWithAllChildren("wailord")
override var portraitScale = 0.45F
override var portraitTranslation = Vec3d(-0.38, 0.8, 6.69)
override var portraitTranslation = Vec3d(-0.38, 0.8, 0.0)
override var profileScale = 0.25F
override var profileTranslation = Vec3d(0.0, 1.2, -10.0)
@@ -21,7 +21,7 @@ class TyrantrumModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val head = getPart("head")
override var portraitTranslation = Vec3d(-0.86, 2.0, 5.0)
override var portraitTranslation = Vec3d(-0.86, 2.0, 0.0)
override var portraitScale = 0.59F
override var profileTranslation = Vec3d(0.02, 1.28, -10.0)
@@ -714,7 +714,6 @@ object PokemonModelRepository : VaryingModelRepository<PokemonEntity, PokemonPos
inbuilt("rowlet_hisui_bias", ::RowletHisuiBiasModel)
inbuilt("dartrix_hisui_bias", ::DartrixHisuiBiasModel)
inbuilt("decidueye_hisuian", ::DecidueyeHisuianModel)
inbuilt("smeargle", ::SmeargleModel)
}
override fun loadJsonPoser(json: String): (Bone) -> PokemonPoseableModel {
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.item.ability.AbilityChanger
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker.after
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.scheduling.taskBuilder
import com.cobblemon.mod.common.api.text.green
@@ -26,13 +25,10 @@ import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.trade.ActiveTrade
import com.cobblemon.mod.common.trade.DummyTradeParticipant
import com.cobblemon.mod.common.trade.PlayerTradeParticipant
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.toPokemon
import com.google.gson.GsonBuilder
@@ -65,22 +61,6 @@ object TestCommand {
}
try {
val player = context.source.entity as ServerPlayerEntity
val evolutionEntity = GenericBedrockEntity(world = player.world)
evolutionEntity?.apply {
category = cobblemonResource("evolution")
colliderHeight = 1.5F
colliderWidth = 1.5F
scale = 1F
syncAge = true // Otherwise particle animation will be starting from zero even if you come along partway through
setPosition(player.x, player.y, player.z + 4)
}
player.world.spawnEntity(evolutionEntity)
after(seconds = 0.5F) {
player.sendPacket(PlayPoseableAnimationPacket(evolutionEntity.id, setOf("evolution:animation.evolution.evolution"), emptySet()))
}
// readBerryDataFromCSV()
// this.testClosestBattle(context)
@@ -20,7 +20,6 @@ import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokeball.catching.CaptureContext
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.scheduling.Schedulable
@@ -58,7 +57,6 @@ import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket
import net.minecraft.particle.ParticleTypes
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundEvents
import net.minecraft.util.Identifier
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.hit.EntityHitResult
import net.minecraft.util.hit.HitResult
@@ -191,7 +189,7 @@ class EmptyPokeBallEntity : ThrownItemEntity, Poseable, WaterDragModifier, Sched
val owner = owner
if (!pokemonEntity.pokemon.isWild()) {
owner?.sendMessage(lang("capture.not_wild", pokemonEntity.exposedSpecies.translatedName).red())
owner?.sendMessage(lang("capture.not_wild", pokemonEntity.pokemon.species.translatedName).red())
return drop()
}
@@ -206,7 +204,7 @@ class EmptyPokeBallEntity : ThrownItemEntity, Poseable, WaterDragModifier, Sched
val hitBattlePokemon = hitActor?.activePokemon?.find { it.battlePokemon?.effectedPokemon?.entity == pokemonEntity }
if (throwerActor == null) {
owner.sendMessage(lang("capture.in_battle", pokemonEntity.exposedSpecies.translatedName).red())
owner.sendMessage(lang("capture.in_battle", pokemonEntity.pokemon.species.translatedName).red())
return drop()
}
@@ -232,13 +230,13 @@ class EmptyPokeBallEntity : ThrownItemEntity, Poseable, WaterDragModifier, Sched
"capture.attempted_capture",
throwerActor.getName(),
pokeBall.item().name,
pokemonEntity.exposedSpecies.translatedName
pokemonEntity.pokemon.species.translatedName
).yellow()
)
battle.sendUpdate(BattleCaptureStartPacket(pokeBall.name, aspects, hitBattlePokemon.getPNX()))
throwerActor.forceChoose(ForcePassActionResponse())
} else if (pokemonEntity.isBusy) {
owner?.sendMessage(lang("capture.busy", pokemonEntity.exposedSpecies.translatedName).red())
owner?.sendMessage(lang("capture.busy", pokemonEntity.pokemon.species.translatedName).red())
return drop()
} else if (owner is ServerPlayerEntity && BattleRegistry.getBattleByParticipatingPlayer(owner) != null) {
owner.sendMessage(lang("you_in_battle").red())
@@ -23,7 +23,6 @@ import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.StringSpeciesFeature
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
@@ -616,7 +615,6 @@ open class PokemonEntity(
override fun interactMob(player: PlayerEntity, hand: Hand) : ActionResult {
val itemStack = player.getStackInHand(hand)
val colorFeatureType = SpeciesFeatures.getFeaturesFor(pokemon.species).find { it is ChoiceSpeciesFeatureProvider && DataKeys.CAN_BE_COLORED in it.keys }
val colorFeature = pokemon.getFeature<StringSpeciesFeature>(DataKeys.CAN_BE_COLORED)
if (itemStack.isOf(Items.SHEARS) && this.isShearable) {
@@ -723,33 +721,13 @@ open class PokemonEntity(
return ActionResult.SUCCESS
}
}
else if (itemStack.item is DyeItem && colorFeatureType != null) {
val currentColor = colorFeature?.value ?: "white"
else if (itemStack.item is DyeItem && colorFeature != null) {
val item = itemStack.item as DyeItem
if (!item.color.name.equals(currentColor, ignoreCase = true)) {
val applied = if (item.color.name.lowercase() == "white" && colorFeature != null) {
this.pokemon.features.remove(colorFeature)
this.pokemon.anyChangeObservable.emit(pokemon)
true
} else if (colorFeature != null) {
colorFeature.value = item.color.name.lowercase()
this.pokemon.markFeatureDirty(colorFeature)
true
} else if (item.color.name.lowercase() != "white") {
val newColorFeature = StringSpeciesFeature(DataKeys.CAN_BE_COLORED, item.color.name.lowercase())
this.pokemon.features.add(newColorFeature)
true
} else {
false
}
if (applied) {
this.pokemon.updateAspects()
if (!player.isCreative) {
itemStack.decrement(1)
}
}
if (item.color.name.lowercase() != colorFeature.value.lowercase()) {
itemStack.decrement(1)
colorFeature.value = item.color.name.lowercase()
this.pokemon.markFeatureDirty(colorFeature)
this.pokemon.updateAspects()
}
}
else if (itemStack.item.equals(Items.WATER_BUCKET) && colorFeature != null) {
@@ -218,6 +218,7 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.MONITOR)
entries.add(CobblemonItems.PC)
entries.add(CobblemonItems.HEALING_MACHINE)
entries.add(CobblemonItems.STADIUM)
entries.add(CobblemonItems.PASTURE)
entries.add(CobblemonItems.GILDED_CHEST)
@@ -269,7 +269,6 @@ class PokemonDTO : Encodable, Decodable {
val featureProviders = SpeciesFeatures
.getFeaturesFor(species)
.filterIsInstance<SynchronizedSpeciesFeatureProvider<*>>()
.filter { it.visible }
val feature = featureProviders.firstNotNullOfOrNull { it(featuresBuffer, speciesFeatureName) }
?: throw IllegalArgumentException("Couldn't find a feature provider to deserialize this feature. Something's wrong.")
it.features.removeIf { it.name == feature.name }
@@ -1,38 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.net.messages.client.pokemon.update
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
class FormUpdatePacket(pokemon: () -> Pokemon, form: FormData) : SingleUpdatePacket<FormData, FormUpdatePacket>(pokemon, form) {
override fun encodeValue(buffer: PacketByteBuf) {
this.value.encode(buffer)
}
override fun set(pokemon: Pokemon, value: FormData) {
pokemon.form = value
}
override val id: Identifier = ID
companion object {
val ID: Identifier = cobblemonResource("packets/form-update")
fun decode(buffer: PacketByteBuf): FormUpdatePacket {
val pokemon = decodePokemon(buffer)
val form = FormData()
form.species = pokemon().species
form.decode(buffer)
return FormUpdatePacket(pokemon, form)
}
}
}
@@ -43,7 +43,6 @@ object SnowstormParticleReader {
val emitterShapeEntityBoundingBoxJson = componentsJson.get("minecraft:emitter_shape_entity_aabb")?.asJsonObject
val emitterLifetimeEventsJson = componentsJson.get("minecraft:emitter_lifetime_events")?.asJsonObject
val dynamicMotionJson = componentsJson.get("minecraft:particle_motion_dynamic")?.asJsonObject
val parametricMotionJson = componentsJson.get("minecraft:particle_motion_parametric")?.asJsonObject
val particleAppearanceJson = componentsJson.get("minecraft:particle_appearance_billboard").asJsonObject
val sizeJson = particleAppearanceJson.get("size")?.asJsonArray
val particleLifetimeJson = componentsJson.get("minecraft:particle_lifetime_expression")?.asJsonObject
@@ -235,22 +234,13 @@ object SnowstormParticleReader {
val motion = if (dynamicMotionJson != null) {
val accelerationExpressions = dynamicMotionJson.get("linear_acceleration")?.asJsonArray?.map { it.asString.asExpression() }
?: listOf(0.0.asExpression(), 0.0.asExpression(), 0.0.asExpression())
val drag = dynamicMotionJson.get("linear_drag_coefficient")?.asString?.asExpression() ?: 0.0.asExpression()
val drag= dynamicMotionJson.get("linear_drag_coefficient")?.asString?.asExpression() ?: 0.0.asExpression()
DynamicParticleMotion(
direction = direction!!,
speed = speed,
acceleration = Triple(accelerationExpressions[0], accelerationExpressions[1], accelerationExpressions[2]),
drag = drag
)
} else if (parametricMotionJson != null) {
val offsetExpressions = parametricMotionJson.get("relative_position")?.asJsonArray?.map { it.asString.asExpression() }
?: listOf(0.0.asExpression(), 0.0.asExpression(), 0.0.asExpression())
val directionExpressions = parametricMotionJson.get("direction")?.asJsonArray?.map { it.asString.asExpression() }
?: listOf(0.0.asExpression(), 0.0.asExpression(), 0.0.asExpression())
ParametricParticleMotion(
offset = Triple(offsetExpressions[0], offsetExpressions[1], offsetExpressions[2]),
direction = Triple(directionExpressions[0], directionExpressions[1], directionExpressions[2])
)
} else {
StaticParticleMotion()
}
@@ -309,19 +299,12 @@ object SnowstormParticleReader {
textureSizeY = uvModeJson.get("texture_height")?.asInt ?: 128
)
}
val motionJson = dynamicMotionJson ?: parametricMotionJson
val parametricParticleRotation = motionJson?.get("rotation")?.asString?.asExpression()
val rotation = if (parametricParticleRotation != null) {
ParametricParticleRotation(expression = parametricParticleRotation)
} else {
DynamicParticleRotation(
startRotation = startRotation,
speed = rotationSpeed,
acceleration = dynamicMotionJson?.get("rotation_acceleration")?.asString?.asExpression() ?: 0.0.asExpression(),
drag = dynamicMotionJson?.get("rotation_drag_coefficient")?.asString?.asExpression() ?: 0.0.asExpression()
)
}
val rotation = DynamicParticleRotation(
startRotation = startRotation,
speed = rotationSpeed,
acceleration = dynamicMotionJson?.get("rotation_acceleration")?.asString?.asExpression() ?: 0.0.asExpression(),
drag = dynamicMotionJson?.get("rotation_drag_coefficient")?.asString?.asExpression() ?: 0.0.asExpression()
)
val tinting = if (colourJson is JsonObject) {
GradientParticleTinting(
interpolant = colourJson.get("interpolant").asString.asExpression(),
@@ -18,12 +18,12 @@ import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
@@ -14,12 +14,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalcula
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.roundToInt
import kotlin.random.Random
import net.minecraft.entity.LivingEntity
@@ -12,12 +12,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.CaptureContext
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.max
import kotlin.math.roundToInt
import kotlin.random.Random
@@ -13,12 +13,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.CaptureContext
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.roundToInt
import kotlin.math.sqrt
import kotlin.random.Random
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptur
import com.cobblemon.mod.common.api.pokeball.catching.calculators.PokedexProgressCaptureMultiplierProvider
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.roundToInt
import kotlin.math.sqrt
import kotlin.random.Random
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptur
import com.cobblemon.mod.common.api.pokeball.catching.calculators.PokedexProgressCaptureMultiplierProvider
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.random.Random
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptur
import com.cobblemon.mod.common.api.pokeball.catching.calculators.PokedexProgressCaptureMultiplierProvider
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.pow
import kotlin.math.roundToInt
import kotlin.random.Random
@@ -13,12 +13,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalcula
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptureProvider
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.roundToInt
@@ -14,12 +14,12 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CriticalCaptur
import com.cobblemon.mod.common.api.pokeball.catching.calculators.PokedexProgressCaptureMultiplierProvider
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
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.pokemon.status.statuses.persistent.SleepStatus
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
import kotlin.math.max
import kotlin.math.pow
import kotlin.math.roundToInt
@@ -472,11 +472,7 @@ open class Pokemon : ShowdownIdentifiable {
SeasonFeatureHandler.updateSeason(this, level, position.toBlockPos())
val entity = PokemonEntity(level, this)
illusion?.start(entity)
val sentOut = entity.setPositionSafely(position)
//If sendout failed, fall back
if (!sentOut) {
entity.setPos(position.x, position.y, position.z)
}
entity.setPositionSafely(position)
mutation(entity)
level.spawnEntity(entity)
state = SentOutState(entity)
@@ -1590,7 +1586,7 @@ open class Pokemon : ShowdownIdentifiable {
}
}
private val _form = registerObservable(SimpleObservable<FormData>()) { FormUpdatePacket({ this }, it) }
private val _form = SimpleObservable<FormData>()
private val _species = registerObservable(SimpleObservable<Species>()) { SpeciesUpdatePacket({ this }, it) }
private val _nickname = registerObservable(SimpleObservable<MutableText?>()) { NicknameUpdatePacket({ this }, it) }
private val _experience = registerObservable(SimpleObservable<Int>()) { ExperienceUpdatePacket({ this }, it) }
@@ -45,7 +45,6 @@ object CobblemonRequirementAdapter : RequirementAdapter {
this.registerType(WeatherRequirement.ADAPTER_VARIANT, WeatherRequirement::class)
this.registerType(StatCompareRequirement.ADAPTER_VARIANT, StatCompareRequirement::class)
this.registerType(StatEqualRequirement.ADAPTER_VARIANT, StatEqualRequirement::class)
this.registerType(AttackDefenceRatioRequirement.ADAPTER_VARIANT, AttackDefenceRatioRequirement::class)
this.registerType(BattleCriticalHitsRequirement.ADAPTER_VARIANT, BattleCriticalHitsRequirement::class)
this.registerType(DamageTakenRequirement.ADAPTER_VARIANT, DamageTakenRequirement::class)
this.registerType(UseMoveRequirement.ADAPTER_VARIANT, UseMoveRequirement::class)
@@ -1,33 +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.pokemon.evolution.requirements
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
import com.cobblemon.mod.common.pokemon.Pokemon
class AttackDefenceRatioRequirement : EvolutionRequirement {
companion object {
const val ADAPTER_VARIANT = "attack_defence_ratio"
}
enum class AttackDefenceRatio {
ATTACK_HIGHER,
DEFENCE_HIGHER,
EQUAL
}
val ratio = AttackDefenceRatio.ATTACK_HIGHER
override fun check(pokemon: Pokemon): Boolean {
return when (ratio) {
AttackDefenceRatio.ATTACK_HIGHER -> pokemon.attack > pokemon.defence
AttackDefenceRatio.DEFENCE_HIGHER -> pokemon.defence > pokemon.attack
AttackDefenceRatio.EQUAL -> pokemon.attack == pokemon.defence
}
}
}
@@ -16,9 +16,4 @@ import net.minecraft.util.Identifier
*
* @author Deltric
*/
open class VolatileStatus(
name: Identifier,
showdownName: String,
applyMessage: String,
removeMessage: String,
) : Status(name, showdownName, applyMessage, removeMessage)
class VolatileStatus(name: Identifier) : Status(name, "", "", "")
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.pokemon.status.statuses.persistent
package com.cobblemon.mod.common.pokemon.status.statuses
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.util.cobblemonResource
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.pokemon.status.statuses.persistent
package com.cobblemon.mod.common.pokemon.status.statuses
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.util.cobblemonResource
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.pokemon.status.statuses.persistent
package com.cobblemon.mod.common.pokemon.status.statuses
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.util.cobblemonResource
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.pokemon.status.statuses.persistent
package com.cobblemon.mod.common.pokemon.status.statuses
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.pokemon.status.statuses.persistent
package com.cobblemon.mod.common.pokemon.status.statuses
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.pokemon.status.statuses.persistent
package com.cobblemon.mod.common.pokemon.status.statuses
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
import com.cobblemon.mod.common.util.cobblemonResource
@@ -1,19 +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.pokemon.status.statuses.nonpersistent
import com.cobblemon.mod.common.pokemon.status.VolatileStatus
import com.cobblemon.mod.common.util.cobblemonResource
class AttractStatus : VolatileStatus(
cobblemonResource("attract"),
"attract",
"cobblemon.battle.attract_start",
"cobblemon.battle.attract_snapped"
)
@@ -1,19 +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.pokemon.status.statuses.nonpersistent
import com.cobblemon.mod.common.pokemon.status.VolatileStatus
import com.cobblemon.mod.common.util.cobblemonResource
class ConfuseStatus : VolatileStatus(
cobblemonResource("confused"),
"confusion",
"cobblemon.battle.confusion_start",
"cobblemon.battle.confusion_snapped"
)
@@ -169,7 +169,6 @@ object DataKeys {
const val PROTECTED_TIME_LEFT = "ProtectedTimeLeft"
const val FORMED = "Formed"
const val CREATED_POKEMON = "CreatedPokemon"
const val HAS_CREATED_POKEMON = "HasCreatedPokemon"
const val FOSSIL_OWNER = "FossilOwner"
const val FOSSIL_STATE = "FossilState"
@@ -2,172 +2,65 @@
"format_version": "1.8.0",
"animations": {
"animation.evolution.evolution": {
"animation_length": 18.45833,
"animation_length": 12,
"bones": {
"root_part": {
"evolution": {
"position": [0, 8, 0]
},
"rotation": {
"rotation": {
"5.0": [0, 0, 0.01],
"5.0417": [0, 1.69062, 0],
"5.0833": [0, 6.2568, 0],
"5.125": [0, 13.45169, 0],
"5.1667": [0, 22.98049, 0],
"5.2083": [0, 34.54587, 0],
"5.25": [0, 47.95457, 0],
"5.2917": [0, 63.03739, 0],
"5.3333": [0, 79.64558, 0],
"5.375": [0, 97.64781, 0],
"5.4167": [0, 116.92776, 0],
"5.4583": [0, 137.38204, 0],
"5.5": [0, 158.91842, 0],
"5.5417": [0, 181.45442, 0],
"5.5833": [0, 204.92016, 0],
"5.625": [0, 229.29923, 0],
"5.6667": [0, 254.4783, 0],
"5.7083": [0, 280.40222, 0],
"5.75": [0, 307.03431, 0],
"5.7917": [0, 334.37233, 0],
"5.8333": [0, 362.31666, 0],
"5.875": [0, 390.84133, 0],
"5.9167": [0, 419.96056, 0],
"5.9583": [0, 449.57842, 0],
"6.0": [0, 479.70479, 0],
"6.0417": [0, 510.30613, 0],
"6.0833": [0, 541.33046, 0],
"6.125": [0, 572.80843, 0],
"6.1667": [0, 604.65184, 0],
"6.2083": [0, 636.90357, 0],
"6.25": [0, 669.48693, 0],
"6.2917": [0, 702.42889, 0],
"6.3333": [0, 735.67367, 0],
"6.375": [0, 769.23809, 0],
"6.4167": [0, 803.07399, 0],
"6.4583": [0, 837.19888, 0],
"6.5": [0, 871.5627, 0],
"6.5417": [0, 906.19102, 0],
"6.5833": [0, 941.02696, 0],
"6.625": [0, 976.10462, 0],
"6.6667": [0, 1011.3691, 0],
"6.7083": [0, 1046.8387, 0],
"6.75": [0, 1082.48407, 0],
"6.7917": [0, 1118.29994, 0],
"6.8333": [0, 1154.28155, 0],
"6.875": [0, 1190.40158, 0],
"6.9167": [0, 1226.67735, 0],
"6.9583": [0, 1263.07209, 0],
"7.0": [0, 1299.59251, 0],
"7.0833": [0, 1372.95248, 0],
"7.2917": [0, 1557.84986, 0],
"7.7083": [0, 1930.52531, 0],
"7.9167": [0, 2116.31891, 0],
"8.0417": [0, 2227.04752, 0],
"8.125": [0, 2300.40749, 0],
"8.1667": [0, 2336.92791, 0],
"8.2083": [0, 2373.32265, 0],
"8.25": [0, 2409.59842, 0],
"8.2917": [0, 2445.71845, 0],
"8.3333": [0, 2481.70006, 0],
"8.375": [0, 2517.51593, 0],
"8.4167": [0, 2553.1613, 0],
"8.4583": [0, 2588.6309, 0],
"8.5": [0, 2623.89538, 0],
"8.5417": [0, 2658.97304, 0],
"8.5833": [0, 2693.80898, 0],
"8.625": [0, 2728.4373, 0],
"8.6667": [0, 2762.80112, 0],
"8.7083": [0, 2796.92601, 0],
"8.75": [0, 2830.76191, 0],
"8.7917": [0, 2864.32633, 0],
"8.8333": [0, 2897.57111, 0],
"8.875": [0, 2930.51307, 0],
"8.9167": [0, 2963.09643, 0],
"8.9583": [0, 2995.34816, 0],
"9.0": [0, 3027.19157, 0],
"9.0417": [0, 3058.66954, 0],
"9.0833": [0, 3089.69387, 0],
"9.125": [0, 3120.29521, 0],
"9.1667": [0, 3150.42158, 0],
"9.2083": [0, 3180.03944, 0],
"9.25": [0, 3209.15867, 0],
"9.2917": [0, 3237.68334, 0],
"9.3333": [0, 3265.62767, 0],
"9.375": [0, 3292.96569, 0],
"9.4167": [0, 3319.59778, 0],
"9.4583": [0, 3345.5217, 0],
"9.5": [0, 3370.70077, 0],
"9.5417": [0, 3395.07984, 0],
"9.5833": [0, 3418.54558, 0],
"9.625": [0, 3441.08158, 0],
"9.6667": [0, 3462.61796, 0],
"9.7083": [0, 3483.07224, 0],
"9.75": [0, 3502.35219, 0],
"9.7917": [0, 3520.35442, 0],
"9.8333": [0, 3536.96261, 0],
"9.875": [0, 3552.04543, 0],
"9.9167": [0, 3565.45413, 0],
"9.9583": [0, 3577.01951, 0],
"10.0": [0, 3586.54831, 0],
"10.0417": [0, 3593.7432, 0],
"10.0833": [0, 3598.30938, 0],
"10.125": [0, "360 * 10", 0]
},
"position": {
"5.25": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"7.125": {
"post": [0, "20 * math.clamp(q.entity_size,1,1.2)", 0],
"lerp_mode": "catmullrom"
},
"10.3333": {
"post": [0, "20 * math.clamp(q.entity_size,1,1.2)", 0],
"lerp_mode": "catmullrom"
},
"10.625": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"10.7083": {
"post": [0, "q.entity_size / 2", 0],
"lerp_mode": "catmullrom"
},
"10.7917": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
},
"scale": {
"4.9167": {
"pre": [1, 1, 1],
"post": [1, 1, 1],
"lerp_mode": "catmullrom"
},
"5.5417": {
"post": [0.75, 0.75, 0.75],
"lerp_mode": "catmullrom"
},
"10.3333": {
"post": [0.75, 0.75, 0.75],
"lerp_mode": "catmullrom"
},
"10.4583": {
"post": [1, 1, 1],
"lerp_mode": "catmullrom"
}
"0.0": [0, 0, 0],
"4.0": [0, -360, 0],
"4.4583": [0, -550, 0],
"9.9583": [0, -4410, 0]
}
}
},
"sound_effects": {
"0.0": {
"effect": "evolution.evolving"
}
},
"particle_effects": {
"0.0": {
"effect": "cobblemon:evo_particles",
"locator": "middle"
}
"effect": "evo_sparkle",
"locator": "sparkles"
},
"3.0": {
"effect": "evo_buildup",
"locator": "sparkles"
},
"4.0": [
{
"effect": "evo_obscuring",
"locator": "clouds"
},
{
"effect": "evo_godrays",
"locator": "sparkles"
}
],
"4.5417": {
"effect": "evo_flyingsparkles",
"locator": "sparkles"
},
"6.0": {
"effect": "evo_bigsparkle",
"locator": "sparkles"
},
"8.6667": {
"effect": "evo_implode",
"locator": "sparkles"
},
"9.0": [
{
"effect": "evo_sparkleburst",
"locator": "sparkles"
},
{
"effect": "evo_smokeburst",
"locator": "sparkles"
},
{
"effect": "evo_sparklefetti",
"locator": "sparkles"
}
]
}
}
}
@@ -1,52 +0,0 @@
{
"format_version": "1.8.0",
"animations": {
"animation.minimize.actor": {
"animation_length": 2,
"bones": {
"root_part": {
"scale": {
"0.0": {
"post": [1, 1, 1],
"lerp_mode": "catmullrom"
},
"0.2917": {
"post": [0.75, 0.75, 0.75],
"lerp_mode": "catmullrom"
},
"0.5417": {
"post": [0.9, 0.9, 0.9],
"lerp_mode": "catmullrom"
},
"0.7917": {
"post": [0.5, 0.5, 0.5],
"lerp_mode": "catmullrom"
},
"1.0417": {
"post": [0.7, 0.7, 0.7],
"lerp_mode": "catmullrom"
},
"1.2917": {
"post": [0.25, 0.25, 0.25],
"lerp_mode": "catmullrom"
},
"1.75": {
"post": [0.25, 0.25, 0.25],
"lerp_mode": "catmullrom"
},
"2.0": {
"post": [1, 1, 1],
"lerp_mode": "catmullrom"
}
}
}
},
"particle_effects": {
"0.9167": {
"effect": "cobblemon:minimize_actor",
"locator": "root"
}
}
}
}
}
@@ -1,62 +0,0 @@
{
"format_version": "1.8.0",
"animations": {
"animation.quickattack.actor": {
"animation_length": 1.75,
"bones": {
"root_part": {
"position": {
"1.0417": {
"pre": [0, 0, 0],
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.125": {
"post": [0, 0, -10],
"lerp_mode": "catmullrom"
},
"1.2083": {
"post": [0, 0, -30],
"lerp_mode": "catmullrom"
},
"1.375": {
"post": [0, 0, -40],
"lerp_mode": "catmullrom"
},
"1.4583": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
},
"1.5417": {
"post": [0, 0, -10],
"lerp_mode": "catmullrom"
},
"1.75": {
"post": [0, 0, 0],
"lerp_mode": "catmullrom"
}
},
"scale": {
"1.0833": [1, 1, 1],
"1.125": {"pre": [1, 1, 1], "post": [0, 0, 0]},
"1.1667": {"pre": [0, 0, 0], "post": [1, 1, 1]},
"1.2083": {"pre": [1, 1, 1], "post": [0, 0, 0]},
"1.6667": {"pre": [0, 0, 0], "post": [1, 1, 1]}
}
}
},
"particle_effects": {
"0.75": {
"effect": "cobblemon:quickattack_dust"
},
"0.875": {
"effect": "cobblemon:quickattack_dashlines",
"locator": "middle"
},
"1.6667": {
"effect": "cobblemon:quickattack_dust"
}
}
}
}
}
@@ -5,6 +5,7 @@
"transformTicks": 0,
"poseTypes": ["NONE"],
"animations": [
"bedrock(evolution, evolution)"
]
}
}
@@ -9,16 +9,19 @@
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": "8 * math.clamp(q.entity_size,1,2)",
"spawn_rate": "8 * v.entity_radius",
"max_particles": 100
},
"minecraft:emitter_lifetime_once": {
"active_time": 2
},
"minecraft:emitter_shape_disc": {
"offset": [0, "math.random(-1,1) * math.clamp(q.entity_size,1,2)", 0],
"radius": "math.clamp(q.entity_size,1,2) * 1.5 + math.random(0.2,1) * math.clamp(q.entity_size,1,2)",
"offset": [0, "math.random(-1,1) * v.entity_radius", 0],
"radius": "v.entity_radius * 1.5 + math.random(0,0.5) * v.entity_radius",
"surface_only": true,
"direction": "outwards"
},
@@ -28,7 +31,7 @@
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": ["0.3 * math.clamp(q.entity_size,1,4)", "0.3 * math.clamp(q.entity_size,1,4)"],
"size": ["0.3 * v.entity_radius", "0.3 * v.entity_radius"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
@@ -9,9 +9,8 @@
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": "v.emitter_age * 10",
@@ -21,19 +20,19 @@
"active_time": 5
},
"minecraft:emitter_shape_sphere": {
"radius": "math.clamp(math.clamp(q.entity_size, 1,4)* 2, 1, 2)",
"radius": "v.entity_radius * 2",
"surface_only": true,
"direction": "inwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "0.7 * math.clamp(q.entity_size, 1, 1.1)"
"max_lifetime": 1
},
"minecraft:particle_initial_speed": "0.125 * math.clamp(q.entity_size,1,4)",
"minecraft:particle_initial_speed": "0.125 * v.entity_radius",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": -4.5
},
"minecraft:particle_appearance_billboard": {
"size": ["math.clamp(math.clamp(q.entity_size, 1,2), 1, 2)/8", "math.clamp(math.clamp(q.entity_size, 1,2), 1, 2)/8"],
"size": ["v.entity_radius/8", "v.entity_radius/8"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
@@ -9,15 +9,18 @@
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": "10 * (math.clamp(q.entity_size,1,2)/2) + 5",
"spawn_rate": "10 * (v.entity_radius/2) + 5",
"max_particles": 100
},
"minecraft:emitter_lifetime_once": {
"active_time": 4
},
"minecraft:emitter_shape_sphere": {
"radius": "math.clamp(q.entity_size,1,2)",
"radius": "v.entity_radius",
"surface_only": true,
"direction": "outwards"
},
@@ -27,19 +30,19 @@
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4)*90"
},
"minecraft:particle_initial_speed": "math.random(4,6) * math.clamp(q.entity_size,1,2)",
"minecraft:particle_initial_speed": "math.random(4,6) * v.entity_radius",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 2
},
"minecraft:particle_appearance_billboard": {
"size": ["0.2 * math.clamp(q.entity_size,1,2)", "0.2 * math.clamp(q.entity_size,1,2)"],
"size": ["0.2 * v.entity_radius", "0.2 * v.entity_radius"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 32,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"size_UV": [0, 8],
"step_UV": [0, 8],
"frames_per_second": 24,
"max_frame": 4,
@@ -47,10 +50,6 @@
}
}
},
"minecraft:particle_motion_collision": {
"collision_drag": 1,
"coefficient_of_restitution": 1
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
@@ -9,9 +9,8 @@
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 12,
@@ -31,7 +30,7 @@
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": ["(6/128) * 1 * v.particle_age * math.clamp(q.entity_size,1,10)", "3 * v.particle_age * math.clamp(q.entity_size,1,10)"],
"size": ["(6/128) * 2 * v.particle_age * v.entity_radius", "3 * v.particle_age * v.entity_radius"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 6,
@@ -1,57 +0,0 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:evo_godrays_small",
"basic_render_parameters": {
"material": "particles_blend",
"texture": "textures/particles/lightbeam"
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
},
"minecraft:emitter_rate_steady": {
"spawn_rate": 12,
"max_particles": 100
},
"minecraft:emitter_lifetime_once": {
"active_time": 3
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
},
"minecraft:particle_initial_spin": {
"rotation": "v.emitter_age/v.emitter_lifetime*360*6 + v.emitter_age/v.emitter_lifetime*360*math.pi + v.emitter_random_1*360",
"rotation_rate": "math.random(-20,20)"
},
"minecraft:particle_initial_speed": 0,
"minecraft:particle_motion_dynamic": {},
"minecraft:particle_appearance_billboard": {
"size": ["(6/128) * 1 * v.particle_age * math.clamp(q.entity_size,1,2)", "2 * v.particle_age * math.clamp(q.entity_size,1,2)"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 6,
"texture_height": 128,
"uv": [0, 0],
"uv_size": [6, 128]
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#0037FFF7",
"0.24": "#FFFF9BAF",
"0.5": "#FFFFF864",
"0.8": "#FFB63EFB",
"1.0": "#0082F8FF"
}
}
}
}
}
}
@@ -9,9 +9,8 @@
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_instant": {
"num_particles": 64
@@ -20,20 +19,20 @@
"active_time": 5
},
"minecraft:emitter_shape_sphere": {
"radius": "math.clamp(q.entity_size,1,2) * 3",
"radius": "v.entity_radius * 4",
"surface_only": true,
"direction": "inwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "0.3 * math.clamp(q.entity_size,1,2)"
"max_lifetime": 0.4
},
"minecraft:particle_initial_speed": "28 * math.clamp(q.entity_size,1,2)",
"minecraft:particle_initial_speed": "28 * v.entity_radius",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["math.random(-40,40)/2", "math.random(-40,40)/2", "math.random(-40,40)/2"],
"linear_drag_coefficient": 6
},
"minecraft:particle_appearance_billboard": {
"size": ["math.clamp(q.entity_size,1,2)/8", "math.clamp(q.entity_size,1,2)/8"],
"size": ["v.entity_radius/8", "v.entity_radius/8"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
@@ -0,0 +1,52 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:evo_obscure_layer1",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/glowing_smoke_cyan"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 0]
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.entity_radius = 1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": "v.entity_radius * 20",
"max_particles": 50
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.8
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.8
},
"minecraft:particle_initial_spin": {
"rotation": "math.random(-360,360)"
},
"minecraft:particle_motion_parametric": {
"relative_position": ["Math.cos((variable.particle_age * 360 / 2) + v.particle_random_2*(360*2) * v.entity_radius * 3)", 0, "Math.sin((variable.particle_age * 360 / 2) + v.particle_random_2*(360*2) * v.entity_radius * 3)"]
},
"minecraft:particle_appearance_billboard": {
"size": [0.2, 0.2],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 48,
"uv": [0, 8],
"uv_size": [8, 8]
}
}
}
}
}
@@ -0,0 +1,68 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:evo_obscure_layer2",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/glowing_smoke_cyan"
}
},
"curves": {
"variable.pop": {
"type": "linear",
"input": "v.particle_age ",
"horizontal_range": "v.particle_lifetime ",
"nodes": [1, 1, 0]
},
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 0]
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.entity_radius = 1;"
},
"minecraft:emitter_rate_instant": {
"num_particles": 20
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_disc": {
"radius": "v.entity_radius",
"surface_only": true,
"direction": "outwards"
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 2
},
"minecraft:particle_initial_spin": {
"rotation": "math.random(-360,360)"
},
"minecraft:particle_initial_speed": 5,
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -1, 0],
"linear_drag_coefficient": 2
},
"minecraft:particle_appearance_billboard": {
"size": ["0.4 * v.size", "0.4 * v.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 48,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [0, 8],
"frames_per_second": 6,
"max_frame": 6
}
}
}
}
}
}
@@ -0,0 +1,52 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:evo_obscure_swirl",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/glowing_smoke_cyan"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [1, 0]
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.entity_radius = 1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": "v.entity_radius * 10",
"max_particles": 50
},
"minecraft:emitter_lifetime_once": {
"active_time": 2.5
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1.5
},
"minecraft:particle_initial_spin": {
"rotation": "math.random(-360,360)"
},
"minecraft:particle_motion_parametric": {
"relative_position": ["Math.cos((variable.particle_age * 360 / 2) + (v.particle_random_2 * 360) * v.entity_radius * 3)", "-1.5 + v.particle_age / 1.1", "Math.sin((variable.particle_age * 360 / 2) + (v.particle_random_2 * 360) * v.entity_radius * 3)"]
},
"minecraft:particle_appearance_billboard": {
"size": [0.2, 0.2],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 48,
"uv": [0, 8],
"uv_size": [8, 8]
}
}
}
}
}
@@ -9,18 +9,21 @@
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "v.entity_radius = v.entity_radius == 0 ? 1 : v.entity_radius;variable.entity_radius = 1;"
},
"minecraft:emitter_local_space": {
"position": true,
"rotation": true
},
"minecraft:emitter_rate_instant": {
"num_particles": "math.clamp(350 * math.clamp(q.entity_size,1,2), 10, 500)"
"num_particles": "350 * v.entity_radius"
},
"minecraft:emitter_lifetime_once": {
"active_time": 5
},
"minecraft:emitter_shape_sphere": {
"radius": "math.clamp(q.entity_size,0.8,1) + (2.5 / math.clamp(q.entity_size,0.5,2))",
"radius": "v.entity_radius + 2",
"surface_only": true,
"direction": "inwards"
},
@@ -30,13 +33,13 @@
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4) * 90"
},
"minecraft:particle_initial_speed": "7 + math.clamp(q.entity_size,1,4)/2 * v.particle_random_1",
"minecraft:particle_initial_speed": "7 + v.entity_radius/2 * v.particle_random_1",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["math.random(-1,1) * math.clamp(q.entity_size, 1,100) * 1.3", "math.random(-1,1) * math.clamp(q.entity_size, 1,100) * 1.3", "math.random(-1,1) * math.clamp(q.entity_size, 1,100) * 1.3 "],
"linear_drag_coefficient": "3 + math.clamp(q.entity_size, 1,100)/2 * v.particle_random_1"
"linear_acceleration": ["math.random(-1,1) * v.entity_radius * 1.3", "math.random(-1,1) * v.entity_radius * 1.3", "math.random(-1,1) * v.entity_radius * 1.3 "],
"linear_drag_coefficient": "3 + v.entity_radius/2 * v.particle_random_1"
},
"minecraft:particle_appearance_billboard": {
"size": ["0.175 * math.clamp(q.entity_size,1,2)", "0.175 * math.clamp(q.entity_size,1,2)"],
"size": ["0.175 * v.entity_radius", "0.175 * v.entity_radius"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
@@ -51,16 +54,7 @@
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_random_4",
"gradient": {
"0.0": "#FFFFFFFF",
"0.22": "#FFCCFFFC",
"0.56": "#FFDCE5FE",
"0.77": "#FFFADDFE",
"1.0": "#FF86FBFF"
}
}
"color": [1, 1, 1, 1]
}
}
}
@@ -5,81 +5,110 @@
"identifier": "cobblemon:evo_particles",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/glowing_dots_cyan"
"texture": "textures/blocks/wool_colored_white"
}
},
"events": {
"event_sparkle": {
"particle_effect": {
"effect": "cobblemon:evo_sparkle",
"type": "emitter_bound"
}
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
},
"expression": ""
},
"event_buildup": {
"particle_effect": {
"effect": "cobblemon:evo_buildup",
"type": "emitter_bound"
}
},
"event_flyingsparkles": {
"particle_effect": {
"effect": "cobblemon:evo_flyingsparkles",
"type": "emitter_bound"
}
},
"event_bigsparkle": {
"particle_effect": {
"effect": "cobblemon:evo_bigsparkle",
"type": "emitter_bound"
}
},
"event_sparklefetti": {
"particle_effect": {
"effect": "cobblemon:evo_sparklefetti",
"type": "emitter_bound"
}
},
"event_sparkleburst": {
"particle_effect": {
"effect": "cobblemon:evo_sparkleburst",
"type": "particle"
}
},
"event_godrays": {
"particle_effect": {
"effect": "cobblemon:evo_godrays",
"type": "emitter_bound"
}
},
"event_implode": {
"particle_effect": {
"effect": "cobblemon:evo_implode",
"type": "particle"
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_obscuring": {
"particle_effect": {
"effect": "cobblemon:evo_obscuring",
"type": "emitter_bound"
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_color_godrays": {
"event_flyingsparkles": {
"particle_effect": {
"effect": "cobblemon:evo_godrays_small",
"type": "emitter_bound"
"effect": "cobblemon:evo_flyingsparkles",
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_bigsparkle": {
"particle_effect": {
"effect": "cobblemon:evo_bigsparkle",
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_sparklefetti": {
"particle_effect": {
"effect": "cobblemon:evo_sparklefetti",
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_sparkleburst": {
"particle_effect": {
"effect": "cobblemon:evo_sparkleburst",
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_smokeburst": {
"particle_effect": {
"effect": "cobblemon:evo_smokeburst",
"type": "emitter_bound"
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_godrays": {
"particle_effect": {
"effect": "cobblemon:evo_godrays",
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_implode": {
"particle_effect": {
"effect": "cobblemon:evo_implode",
"type": "particle",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_swirl": {
"particle_effect": {
"effect": "cobblemon:evo_obscure_swirl",
"type": "emitter",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_swirlend": {
"particle_effect": {
"effect": "cobblemon:evo_obscure_layer2",
"type": "emitter",
"pre_effect_expression": "variable.entity_radius = 1;"
}
},
"event_obscure_spin": {
"particle_effect": {
"effect": "cobblemon:evo_obscure_layer1",
"type": "emitter"
},
"expression": ""
},
"event_expression": {
"expression": ""
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
"rotation": true
},
"minecraft:emitter_rate_instant": {
"num_particles": 1
@@ -90,13 +119,15 @@
"minecraft:emitter_lifetime_events": {
"creation_event": "event_sparkle",
"timeline": {
"2.00": "event_buildup",
"3.00": "event_buildup",
"5.00": "event_obscuring",
"5.01": "event_color_godrays",
"5.10": "event_godrays",
"5.80": "event_swirl",
"6.00": "event_flyingsparkles",
"7.00": "event_bigsparkle",
"9.00": "event_obscure_spin",
"9.50": "event_godrays",
"9.58": "event_implode",
"9.99": "event_swirlend",
"10.00": "event_smokeburst",
"10.01": "event_sparkleburst",
"10.02": "event_sparklefetti"
@@ -106,6 +137,7 @@
"offset": [0, 1, 0]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1,
"expiration_expression": 1
},
"minecraft:particle_initial_speed": 0,
@@ -114,10 +146,10 @@
"size": [0.2, 0.2],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
"texture_height": 32,
"texture_width": 16,
"texture_height": 16,
"uv": [0, 0],
"uv_size": [1, 1]
"uv_size": [16, 16]
}
}
}
@@ -9,19 +9,18 @@
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_instant": {
"num_particles": "math.clamp(130 * math.clamp(q.entity_size,1,2), 1, 260)"
"num_particles": "150 * v.entity_radius"
},
"minecraft:emitter_lifetime_once": {
"active_time": 1
},
"minecraft:emitter_shape_sphere": {
"offset": [0, -0.1, 0],
"radius": "math.clamp(q.entity_size, 1,3)/ 2",
"radius": "v.entity_radius/2",
"surface_only": true,
"direction": "outwards"
},
@@ -31,13 +30,13 @@
"minecraft:particle_initial_spin": {
"rotation": "math.random_integer(1,4)*90"
},
"minecraft:particle_initial_speed": "math.clamp(math.random(10,12.5) * q.entity_size, 9, 20 )",
"minecraft:particle_initial_speed": "math.random(10,12.5)",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": ["(v.particle_random_2*15 - 15/2) + (math.random(-4,4) * math.clamp(q.entity_size,1,2))", "(v.particle_random_3*8 - 4) + (math.random(-4,4) * math.clamp(q.entity_size,1,2))", "(v.particle_random_4*15 - 15/2) + (math.random(-4,4) * math.clamp(q.entity_size,1,2))"],
"linear_drag_coefficient": "math.random(4,5) / (math.clamp(q.entity_size,1,2))"
"linear_acceleration": ["(v.particle_random_2*15 - 15/2) + math.random(-4,4)", "(v.particle_random_3*8 - 4) + math.random(-4,4)", "(v.particle_random_4*15 - 15/2) + math.random(-4,4)"],
"linear_drag_coefficient": "math.random(4,5)"
},
"minecraft:particle_appearance_billboard": {
"size": ["0.15 * math.clamp(q.entity_size,1,2)", "0.15 * math.clamp(q.entity_size,1,2)"],
"size": [0.15, 0.15],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
@@ -46,7 +45,7 @@
"base_UV": [0, 0],
"size_UV": [8, 8],
"step_UV": [0, 8],
"max_frame": 6,
"max_frame": 7,
"stretch_to_lifetime": true
}
}
@@ -57,13 +56,12 @@
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_random_4",
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFFFFFF",
"0.22": "#FFCCFFFC",
"0.56": "#FFD0DAFE",
"0.77": "#FFFAD8FF",
"1.0": "#FFFFFFFF"
"0.18": "#B5FFFFFF",
"0.5": "#A3FFFFFF",
"1.0": "#FF00FFF6"
}
}
}
@@ -9,19 +9,18 @@
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": "math.clamp(10 * math.clamp(q.entity_size,1,2), 10, 100)",
"spawn_rate": "math.clamp(10 * v.entity_radius, 10, 100)",
"max_particles": 100
},
"minecraft:emitter_lifetime_looping": {
"active_time": 5
},
"minecraft:emitter_shape_point": {
"offset": ["math.sin(v.emitter_age*360*3+v.emitter_random_1*360)*(math.clamp(q.entity_size,1,2)+0.1)", -0.5, "math.cos(v.emitter_age*360*3+v.emitter_random_1*360)*(math.clamp(q.entity_size,1,2)+0.1)"]
"offset": ["math.sin(v.emitter_age*360*3+v.emitter_random_1*360)*(v.entity_radius+0.2)", -0.5, "math.cos(v.emitter_age*360*3+v.emitter_random_1*360)*(v.entity_radius+0.2)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1
@@ -9,14 +9,17 @@
}
},
"components": {
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_instant": {
"num_particles": "35 * math.clamp(q.entity_size,1,2)"
"num_particles": "35 * v.entity_radius"
},
"minecraft:emitter_lifetime_once": {
"active_time": "0.5 * math.clamp(q.entity_size,1,2)"
"active_time": "0.5 * v.entity_radius"
},
"minecraft:emitter_shape_sphere": {
"radius": "math.clamp(q.entity_size,1,2)/2",
"radius": "v.entity_radius/2",
"surface_only": true,
"direction": "outwards"
},
@@ -29,7 +32,7 @@
"linear_drag_coefficient": 4
},
"minecraft:particle_appearance_billboard": {
"size": ["0.125 * math.clamp(q.entity_size,1,2) + 0.1", "0.125 * math.clamp(q.entity_size,1,2) + 0.1"],
"size": ["0.125 * v.entity_radius + 0.1", "0.125 * v.entity_radius + 0.1"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 8,
@@ -17,13 +17,12 @@
}
},
"components": {
"minecraft:emitter_local_space": {
"position": true,
"rotation": false
"minecraft:emitter_initialization": {
"creation_expression": "variable.entity_radius = 1;"
},
"minecraft:emitter_rate_steady": {
"spawn_rate": "200 * math.clamp(q.entity_size,1,4)",
"max_particles": "15 * math.clamp(q.entity_size,1,4)"
"spawn_rate": "200 * v.entity_radius",
"max_particles": "15 * v.entity_radius"
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
@@ -32,19 +31,19 @@
"offset": [0, 0.1, 0],
"radius": 0.1,
"surface_only": true,
"direction": ["math.random(-0.6,0.6)", "math.random(0.6,1)", "math.random(-0.6,0.6)"]
"direction": ["math.random(-0.6,0.6)", "math.random(0.6,0.4)", "math.random(-0.6,0.6)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": "v.particle_random_1 + 1.5"
"max_lifetime": "v.particle_random_1 + 1"
},
"minecraft:particle_initial_speed": "math.random(4,8) * math.clamp(q.entity_size,1,4)",
"minecraft:particle_initial_speed": "math.random(4,8) * v.entity_radius",
"minecraft:particle_motion_dynamic": {
"linear_acceleration": [0, -10, 0],
"linear_drag_coefficient": 0.1,
"linear_acceleration": [0, -12, 0],
"linear_drag_coefficient": 1.5,
"rotation_drag_coefficient": 1
},
"minecraft:particle_appearance_billboard": {
"size": ["math.clamp(0.125 * math.clamp(q.entity_size,1,4), 0.075, 0.2)", "math.clamp(0.125 * math.clamp(q.entity_size,1,4), 0.075, 0.2)"],
"size": ["math.clamp(0.125 * v.entity_radius, 0.075, 0.2)", "math.clamp(0.125 * v.entity_radius, 0.075, 0.2)"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 16,
@@ -1,86 +0,0 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:confused_actor",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/chirp"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0]
}
},
"events": {
"event_bird2": {
"particle_effect": {
"effect": "cobblemon:confused_bird2",
"type": "particle"
}
},
"event_bird3": {
"particle_effect": {
"effect": "cobblemon:confused_bird3",
"type": "particle"
}
},
"event_bird4": {
"particle_effect": {
"effect": "cobblemon:confused_bird4",
"type": "particle"
}
},
"event_bird5": {
"particle_effect": {
"effect": "cobblemon:confused_bird5",
"type": "particle"
}
},
"event_bird6": {
"particle_effect": {
"effect": "cobblemon:confused_bird6",
"type": "particle"
}
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.5
},
"minecraft:emitter_lifetime_events": {
"creation_event": ["event_bird2", "event_bird3", "event_bird4", "event_bird5", "event_bird6"]
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1.5
},
"minecraft:particle_motion_parametric": {
"relative_position": ["math.clamp(q.entity_radius/1.5,0.4,999)*math.sin(v.particle_age/1.5*360)", "0.2+(q.entity_height*1)+0.1*math.sin(v.particle_age)+(math.sin(v.particle_age*580)/25)", "math.clamp(q.entity_radius/1.5,0.4,999)*-math.cos(v.particle_age/1.5*360)"]
},
"minecraft:particle_appearance_billboard": {
"size": ["(math.clamp(q.entity_height*1.25,1.25,2.5)*v.size)*1.25", "math.clamp(q.entity_height*1.25,1.25,2.5)*v.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 192,
"texture_height": 9,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [12, 9],
"step_UV": [12, 0],
"frames_per_second": 12,
"max_frame": 16,
"loop": true
}
}
}
}
}
}
@@ -1,51 +0,0 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:confused_bird2",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/chirp"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.5
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1.5
},
"minecraft:particle_motion_parametric": {
"relative_position": ["math.clamp(q.entity_radius/1.5,0.4,999)*-math.sin(v.particle_age/1.5*360)", "0.2+(q.entity_height*1)+0.1*math.sin(v.particle_age)-(math.sin(v.particle_age*580)/25)", "math.clamp(q.entity_radius/1.5,0.4,999)*math.cos(v.particle_age/1.5*360)"]
},
"minecraft:particle_appearance_billboard": {
"size": ["(math.clamp(q.entity_height*1.25,1.25,2.5)*v.size)*1.25", "math.clamp(q.entity_height*1.25,1.25,2.5)*v.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 192,
"texture_height": 9,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [12, 9],
"step_UV": [12, 0],
"frames_per_second": 12,
"max_frame": 16,
"loop": true
}
}
}
}
}
}
@@ -1,51 +0,0 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:confused_bird3",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/chirp"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.5
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1.5
},
"minecraft:particle_motion_parametric": {
"relative_position": ["math.clamp(q.entity_radius/1.5,0.4,999)*math.sin(60+v.particle_age/1.5*360)", "0.2+(q.entity_height*1)+0.1*math.sin(v.particle_age)-(math.sin(v.particle_age*580)/25)", "math.clamp(q.entity_radius/1.5,0.4,999)*-math.cos(60+v.particle_age/1.5*360)"]
},
"minecraft:particle_appearance_billboard": {
"size": ["(math.clamp(q.entity_height*1.25,1.25,2.5)*v.size)*1.25", "math.clamp(q.entity_height*1.25,1.25,2.5)*v.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 192,
"texture_height": 9,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [12, 9],
"step_UV": [12, 0],
"frames_per_second": 12,
"max_frame": 16,
"loop": true
}
}
}
}
}
}
@@ -1,51 +0,0 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:confused_bird4",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/chirp"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.5
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1.5
},
"minecraft:particle_motion_parametric": {
"relative_position": ["math.clamp(q.entity_radius/1.5,0.4,999)*math.sin(-60+v.particle_age/1.5*360)", "0.2+(q.entity_height*1)+0.1*math.sin(v.particle_age)-(math.sin(v.particle_age*580)/25)", "math.clamp(q.entity_radius/1.5,0.4,999)*-math.cos(-60+v.particle_age/1.5*360)"]
},
"minecraft:particle_appearance_billboard": {
"size": ["(math.clamp(q.entity_height*1.25,1.25,2.5)*v.size)*1.25", "math.clamp(q.entity_height*1.25,1.25,2.5)*v.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 192,
"texture_height": 9,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [12, 9],
"step_UV": [12, 0],
"frames_per_second": 12,
"max_frame": 16,
"loop": true
}
}
}
}
}
}
@@ -1,51 +0,0 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:confused_bird5",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/chirp"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.5
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1.5
},
"minecraft:particle_motion_parametric": {
"relative_position": ["math.clamp(q.entity_radius/1.5,0.4,999)*math.sin(120+v.particle_age/1.5*360)", "0.2+(q.entity_height*1)+0.1*math.sin(v.particle_age)+(math.sin(v.particle_age*580)/25)", "math.clamp(q.entity_radius/1.5,0.4,999)*-math.cos(120+v.particle_age/1.5*360)"]
},
"minecraft:particle_appearance_billboard": {
"size": ["(math.clamp(q.entity_height*1.25,1.25,2.5)*v.size)*1.25", "math.clamp(q.entity_height*1.25,1.25,2.5)*v.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 192,
"texture_height": 9,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [12, 9],
"step_UV": [12, 0],
"frames_per_second": 12,
"max_frame": 16,
"loop": true
}
}
}
}
}
}
@@ -1,51 +0,0 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:confused_bird6",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/chirp"
}
},
"curves": {
"variable.size": {
"type": "linear",
"input": "v.particle_age",
"horizontal_range": "v.particle_lifetime",
"nodes": [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0]
}
},
"components": {
"minecraft:emitter_rate_instant": {
"num_particles": 1
},
"minecraft:emitter_lifetime_once": {
"active_time": 1.5
},
"minecraft:emitter_shape_point": {},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 1.5
},
"minecraft:particle_motion_parametric": {
"relative_position": ["math.clamp(q.entity_radius/1.5,0.4,999)*math.sin(-120+v.particle_age/1.5*360)", "0.2+(q.entity_height*1)+0.1*math.sin(v.particle_age)+(math.sin(v.particle_age*580)/25)", "math.clamp(q.entity_radius/1.5,0.4,999)*-math.cos(-120+v.particle_age/1.5*360)"]
},
"minecraft:particle_appearance_billboard": {
"size": ["(math.clamp(q.entity_height*1.25,1.25,2.5)*v.size)*1.25", "math.clamp(q.entity_height*1.25,1.25,2.5)*v.size"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 192,
"texture_height": 9,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [12, 9],
"step_UV": [12, 0],
"frames_per_second": 12,
"max_frame": 16,
"loop": true
}
}
}
}
}
}
@@ -1,72 +0,0 @@
{
"format_version": "1.10.0",
"particle_effect": {
"description": {
"identifier": "cobblemon:infatuate_actor",
"basic_render_parameters": {
"material": "particles_alpha",
"texture": "textures/particles/attract_heart"
}
},
"events": {
"extrahearts": {
"particle_effect": {
"effect": "cobblemon:infatuate_actorresidual",
"type": "emitter"
}
}
},
"components": {
"minecraft:emitter_rate_steady": {
"spawn_rate": 12,
"max_particles": 10
},
"minecraft:emitter_lifetime_once": {
"active_time": 0.5
},
"minecraft:emitter_lifetime_events": {
"timeline": {
"0.25": "extrahearts"
}
},
"minecraft:emitter_shape_disc": {
"offset": [0, "((variable.particle_random_3-(variable.particle_random_3*0.5))*(q.entity_height*0.6))", 0],
"radius": "math.clamp(q.entity_radius*0.7,0.6,1.3)",
"surface_only": true,
"direction": ["math.random(-1.9,1.9)", "math.random(4,7)", "math.random(-1.5,1.5)"]
},
"minecraft:particle_lifetime_expression": {
"max_lifetime": 0.65
},
"minecraft:particle_initial_speed": "math.random(3,4)",
"minecraft:particle_motion_dynamic": {
"linear_drag_coefficient": 2
},
"minecraft:particle_appearance_billboard": {
"size": ["(0.2+0.125*v.particle_random_2)*math.clamp(q.entity_size*0.5,1,1.75)", "(0.2+0.125*v.particle_random_2)*math.clamp(q.entity_size*0.5,1,1.75)"],
"facing_camera_mode": "rotate_xyz",
"uv": {
"texture_width": 90,
"texture_height": 9,
"flipbook": {
"base_UV": [0, 0],
"size_UV": [9, 9],
"step_UV": [9, 0],
"frames_per_second": 16,
"max_frame": 10
}
}
},
"minecraft:particle_appearance_tinting": {
"color": {
"interpolant": "v.particle_age / v.particle_lifetime",
"gradient": {
"0.0": "#FFFF99B7",
"0.5": "#ffffffff",
"1.0": "#FFFF99B7"
}
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More