forked from mirrors/cobblemon
Compare commits
57
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f70d7ce336 | ||
|
|
5b0a221ade | ||
|
|
af23b82ce5 | ||
|
|
36e78a5af2 | ||
|
|
55621b01b7 | ||
|
|
b828fe2b3a | ||
|
|
b7b10151e1 | ||
|
|
cac6ed843a | ||
|
|
8f5f40c360 | ||
|
|
0e586b4f38 | ||
|
|
62dd487448 | ||
|
|
04ecd9189c | ||
|
|
55be22e942 | ||
|
|
f2e1b3dab4 | ||
|
|
66f98ebf12 | ||
|
|
c1842e42b0 | ||
|
|
e6c2f241d4 | ||
|
|
0f9c282e1f | ||
|
|
7bd5d77b60 | ||
|
|
f7b4d4e65a | ||
|
|
e78f403198 | ||
|
|
4ca91cc8d8 | ||
|
|
1518181f6b | ||
|
|
b915237c8d | ||
|
|
bb41a72067 | ||
|
|
fbb8492c75 | ||
|
|
c07aef04b1 | ||
|
|
6ff4befb04 | ||
|
|
a858d4f532 | ||
|
|
28fc273b26 | ||
|
|
fc89757a09 | ||
|
|
243c9abfd1 | ||
|
|
b871645e9e | ||
|
|
c79916d8a0 | ||
|
|
d503d4a1eb | ||
|
|
a0f75dd090 | ||
|
|
5eceaa849c | ||
|
|
0e0233993a | ||
|
|
56ed5a6412 | ||
|
|
f2e5ecef66 | ||
|
|
ad9e85923a | ||
|
|
bf461297b2 | ||
|
|
5965d5a81b | ||
|
|
4e02ca310d | ||
|
|
3260271d3c | ||
|
|
a77863adab | ||
|
|
455cfeb894 | ||
|
|
fd3c614c2c | ||
|
|
4f3eb7e4ba | ||
|
|
f9a3d2dc0e | ||
|
|
f817c18f4f | ||
|
|
a7e6e638fe | ||
|
|
9ef3ea2932 | ||
|
|
38dcee3327 | ||
|
|
12b92d3f35 | ||
|
|
dacfb4f1ff | ||
|
|
4086ba73d3 |
@@ -52,6 +52,7 @@
|
||||
- Added a unique set of sounds for Ancient Poké Balls.
|
||||
- Added a sound for using Exp Candy and Rare Candy items.
|
||||
- Added raft platforms for non-swimming, non-flying Pokémon to stand on during battles that take place on the water's surface. (Flying Pokémon will fly over water in battle, and water breathing Pokémon will swim in water during battle.)
|
||||
- Added `hiddenability=false` option to `/spawnpokemon` and `/pokemonedit` commands, allowing the Pokémon's ability to be reverted to a normal ability.
|
||||
|
||||
### Pokémon Added
|
||||
#### Gen 1
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ public abstract class MinecraftDedicatedServerMixin implements ServerInterface {
|
||||
|
||||
@Inject(method = "shouldDiscardEntity", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void cobblemon$allowPokemonSpawns(Entity entity, CallbackInfoReturnable<Boolean> callback) {
|
||||
if(entity instanceof PokemonEntity) {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
callback.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.config.starter.StarterConfig
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.events.AdvancementHandler
|
||||
import com.cobblemon.mod.common.events.FlowHandler
|
||||
import com.cobblemon.mod.common.events.PokedexHandler
|
||||
import com.cobblemon.mod.common.events.ServerTickHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
@@ -288,6 +289,8 @@ object Cobblemon {
|
||||
|
||||
CobblemonEvents.POKEMON_PROPERTY_INITIALISED.emit(Unit)
|
||||
|
||||
FlowHandler.setup()
|
||||
|
||||
ifDedicatedServer {
|
||||
isDedicatedServer = true
|
||||
}
|
||||
|
||||
@@ -276,81 +276,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val CHISELED_BLACK_TUMBLESTONE_BRICKS = this.create("chiseled_black_tumblestone_bricks", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
|
||||
@JvmField
|
||||
val GEM_BUG_BLOCK = this.create("gem_bug_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_DARK_BLOCK = this.create("gem_dark_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_DRAGON_BLOCK = this.create("gem_dragon_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_ELECTRIC_BLOCK = this.create("gem_electric_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_FAIRY_BLOCK = this.create("gem_fairy_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_FIGHTING_BLOCK = this.create("gem_fighting_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_FIRE_BLOCK = this.create("gem_fire_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_FLYING_BLOCK = this.create("gem_flying_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_GHOST_BLOCK = this.create("gem_ghost_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_GRASS_BLOCK = this.create("gem_grass_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_GROUND_BLOCK = this.create("gem_ground_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_ICE_BLOCK = this.create("gem_ice_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_NORMAL_BLOCK = this.create("gem_normal_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_POISON_BLOCK = this.create("gem_poison_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_PSYCHIC_BLOCK = this.create("gem_psychic_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_ROCK_BLOCK = this.create("gem_rock_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_STEEL_BLOCK = this.create("gem_steel_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_WATER_BLOCK = this.create("gem_water_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
|
||||
@JvmField
|
||||
val GEM_BUG_BUDDING = this.create("gem_bug_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_DARK_BUDDING = this.create("gem_dark_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_DRAGON_BUDDING = this.create("gem_dragon_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_ELECTRIC_BUDDING = this.create("gem_electric_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_FAIRY_BUDDING = this.create("gem_fairy_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_FIGHTING_BUDDING = this.create("gem_fighting_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_FIRE_BUDDING = this.create("gem_fire_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_FLYING_BUDDING = this.create("gem_flying_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_GHOST_BUDDING = this.create("gem_ghost_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_GRASS_BUDDING = this.create("gem_grass_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_GROUND_BUDDING = this.create("gem_ground_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_ICE_BUDDING = this.create("gem_ice_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_NORMAL_BUDDING = this.create("gem_normal_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_POISON_BUDDING = this.create("gem_poison_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_PSYCHIC_BUDDING = this.create("gem_psychic_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_ROCK_BUDDING = this.create("gem_rock_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_STEEL_BUDDING = this.create("gem_steel_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@JvmField
|
||||
val GEM_WATER_BUDDING = this.create("gem_water_budding", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
|
||||
|
||||
@JvmField
|
||||
val FIRE_STONE_BLOCK = this.create("fire_stone_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.FIRE).strength(1.0F).sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BIT).lightLevel{13}))
|
||||
@JvmField
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.net.messages.client.data.FlowRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.endsWith
|
||||
import java.util.concurrent.ExecutionException
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
|
||||
/**
|
||||
* Holds all the flows that are loaded from the server's data packs. A flow is foldered under the event identifier,
|
||||
* which can be Cobblemon's namespace but can also be minecraft or any other namespace someone has added hooks for.
|
||||
* The value of the map is a list of MoLang scripts that will execute when that event occurs.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 24th, 2024
|
||||
*/
|
||||
object CobblemonFlows : DataRegistry {
|
||||
override val id = cobblemonResource("flows")
|
||||
override val observable = SimpleObservable<CobblemonFlows>()
|
||||
override val type = PackType.SERVER_DATA
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(FlowRegistrySyncPacket(clientFlows.entries))
|
||||
}
|
||||
|
||||
val runtime by lazy { MoLangRuntime().setup() } // Lazy for if someone adds to generalFunctions in MoLangFunctions
|
||||
|
||||
val clientFlows = hashMapOf<ResourceLocation, MutableList<ExpressionLike>>()
|
||||
val flows = hashMapOf<ResourceLocation, MutableList<ExpressionLike>>()
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
val folderBeforeNameRegex = ".*\\/([^\\/]+)\\/[^\\/]+\$".toRegex()
|
||||
manager.listResources("flows") { path -> path.endsWith(CobblemonScripts.MOLANG_EXTENSION) }.forEach { (identifier, resource) ->
|
||||
resource.openAsReader().use { stream ->
|
||||
stream.buffered().use { reader ->
|
||||
try {
|
||||
val expression = reader.readText().asExpressionLike()
|
||||
val event = folderBeforeNameRegex.find(identifier.path)?.groupValues?.get(1)
|
||||
?: throw IllegalArgumentException("Invalid flow path: $identifier. Should have a folder structure that includes the name of the event being flowed.")
|
||||
if (identifier.path.startsWith("flows/client/")) {
|
||||
clientFlows.getOrPut(ResourceLocation.fromNamespaceAndPath(identifier.namespace, event)) { mutableListOf() }.add(expression)
|
||||
} else {
|
||||
flows.getOrPut(ResourceLocation.fromNamespaceAndPath(identifier.namespace, event)) { mutableListOf() }.add(expression)
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
throw ExecutionException("Error loading MoLang script for flow: $identifier", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cobblemon.LOGGER.info("Loaded ${CobblemonScripts.scripts.size} flows and ${CobblemonScripts.clientScripts.size} client flows")
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
fun run(eventResourceLocation: ResourceLocation, context: Map<String, MoValue>) {
|
||||
flows[eventResourceLocation]?.forEach { it.resolve(runtime, context) }
|
||||
}
|
||||
}
|
||||
@@ -171,14 +171,6 @@ interface CobblemonImplementation {
|
||||
*/
|
||||
fun server(): MinecraftServer?
|
||||
|
||||
/**
|
||||
* Handles platform independent reloading of a [JsonDataRegistry].
|
||||
*
|
||||
* @param registry The [JsonDataRegistry] to reload.
|
||||
* @param manager The [ResourceManager] to reload from.
|
||||
*/
|
||||
fun <T> reloadJsonRegistry(registry: JsonDataRegistry<T>, manager: ResourceManager): HashMap<ResourceLocation, T>
|
||||
|
||||
/**
|
||||
* Registers an item to the [ComposterBlock].
|
||||
*
|
||||
|
||||
@@ -1224,80 +1224,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
//@JvmField
|
||||
//val BINDING_SOIL = blockItem("binding_soil", CobblemonBlocks.BINDING_SOIL)
|
||||
|
||||
@JvmField
|
||||
val GEM_BUG_BLOCK = blockItem("gem_bug_block", CobblemonBlocks.GEM_BUG_BLOCK)
|
||||
@JvmField
|
||||
val GEM_DARK_BLOCK = blockItem("gem_dark_block", CobblemonBlocks.GEM_DARK_BLOCK)
|
||||
@JvmField
|
||||
val GEM_DRAGON_BLOCK = blockItem("gem_dragon_block", CobblemonBlocks.GEM_DRAGON_BLOCK)
|
||||
@JvmField
|
||||
val GEM_ELECTRIC_BLOCK = blockItem("gem_electric_block", CobblemonBlocks.GEM_ELECTRIC_BLOCK)
|
||||
@JvmField
|
||||
val GEM_FAIRY_BLOCK = blockItem("gem_fairy_block", CobblemonBlocks.GEM_FAIRY_BLOCK)
|
||||
@JvmField
|
||||
val GEM_FIGHTING_BLOCK = blockItem("gem_fighting_block", CobblemonBlocks.GEM_FIGHTING_BLOCK)
|
||||
@JvmField
|
||||
val GEM_FIRE_BLOCK = blockItem("gem_fire_block", CobblemonBlocks.GEM_FIRE_BLOCK)
|
||||
@JvmField
|
||||
val GEM_FLYING_BLOCK = blockItem("gem_flying_block", CobblemonBlocks.GEM_FLYING_BLOCK)
|
||||
@JvmField
|
||||
val GEM_GHOST_BLOCK = blockItem("gem_ghost_block", CobblemonBlocks.GEM_GHOST_BLOCK)
|
||||
@JvmField
|
||||
val GEM_GRASS_BLOCK = blockItem("gem_grass_block", CobblemonBlocks.GEM_GRASS_BLOCK)
|
||||
@JvmField
|
||||
val GEM_GROUND_BLOCK = blockItem("gem_ground_block", CobblemonBlocks.GEM_GROUND_BLOCK)
|
||||
@JvmField
|
||||
val GEM_ICE_BLOCK = blockItem("gem_ice_block", CobblemonBlocks.GEM_ICE_BLOCK)
|
||||
@JvmField
|
||||
val GEM_NORMAL_BLOCK = blockItem("gem_normal_block", CobblemonBlocks.GEM_NORMAL_BLOCK)
|
||||
@JvmField
|
||||
val GEM_POISON_BLOCK = blockItem("gem_poison_block", CobblemonBlocks.GEM_POISON_BLOCK)
|
||||
@JvmField
|
||||
val GEM_PSYCHIC_BLOCK = blockItem("gem_psychic_block", CobblemonBlocks.GEM_PSYCHIC_BLOCK)
|
||||
@JvmField
|
||||
val GEM_ROCK_BLOCK = blockItem("gem_rock_block", CobblemonBlocks.GEM_ROCK_BLOCK)
|
||||
@JvmField
|
||||
val GEM_STEEL_BLOCK = blockItem("gem_steel_block", CobblemonBlocks.GEM_STEEL_BLOCK)
|
||||
@JvmField
|
||||
val GEM_WATER_BLOCK = blockItem("gem_water_block", CobblemonBlocks.GEM_WATER_BLOCK)
|
||||
|
||||
@JvmField
|
||||
val GEM_BUG_BUDDING = blockItem("gem_bug_budding", CobblemonBlocks.GEM_BUG_BUDDING)
|
||||
@JvmField
|
||||
val GEM_DARK_BUDDING = blockItem("gem_dark_budding", CobblemonBlocks.GEM_DARK_BUDDING)
|
||||
@JvmField
|
||||
val GEM_DRAGON_BUDDING = blockItem("gem_dragon_budding", CobblemonBlocks.GEM_DRAGON_BUDDING)
|
||||
@JvmField
|
||||
val GEM_ELECTRIC_BUDDING = blockItem("gem_electric_budding", CobblemonBlocks.GEM_ELECTRIC_BUDDING)
|
||||
@JvmField
|
||||
val GEM_FAIRY_BUDDING = blockItem("gem_fairy_budding", CobblemonBlocks.GEM_FAIRY_BUDDING)
|
||||
@JvmField
|
||||
val GEM_FIGHTING_BUDDING = blockItem("gem_fighting_budding", CobblemonBlocks.GEM_FIGHTING_BUDDING)
|
||||
@JvmField
|
||||
val GEM_FIRE_BUDDING = blockItem("gem_fire_budding", CobblemonBlocks.GEM_FIRE_BUDDING)
|
||||
@JvmField
|
||||
val GEM_FLYING_BUDDING = blockItem("gem_flying_budding", CobblemonBlocks.GEM_FLYING_BUDDING)
|
||||
@JvmField
|
||||
val GEM_GHOST_BUDDING = blockItem("gem_ghost_budding", CobblemonBlocks.GEM_GHOST_BUDDING)
|
||||
@JvmField
|
||||
val GEM_GRASS_BUDDING = blockItem("gem_grass_budding", CobblemonBlocks.GEM_GRASS_BUDDING)
|
||||
@JvmField
|
||||
val GEM_GROUND_BUDDING = blockItem("gem_ground_budding", CobblemonBlocks.GEM_GROUND_BUDDING)
|
||||
@JvmField
|
||||
val GEM_ICE_BUDDING = blockItem("gem_ice_budding", CobblemonBlocks.GEM_ICE_BUDDING)
|
||||
@JvmField
|
||||
val GEM_NORMAL_BUDDING = blockItem("gem_normal_budding", CobblemonBlocks.GEM_NORMAL_BUDDING)
|
||||
@JvmField
|
||||
val GEM_POISON_BUDDING = blockItem("gem_poison_budding", CobblemonBlocks.GEM_POISON_BUDDING)
|
||||
@JvmField
|
||||
val GEM_PSYCHIC_BUDDING = blockItem("gem_psychic_budding", CobblemonBlocks.GEM_PSYCHIC_BUDDING)
|
||||
@JvmField
|
||||
val GEM_ROCK_BUDDING = blockItem("gem_rock_budding", CobblemonBlocks.GEM_ROCK_BUDDING)
|
||||
@JvmField
|
||||
val GEM_STEEL_BUDDING = blockItem("gem_steel_budding", CobblemonBlocks.GEM_STEEL_BUDDING)
|
||||
@JvmField
|
||||
val GEM_WATER_BUDDING = blockItem("gem_water_budding", CobblemonBlocks.GEM_WATER_BUDDING)
|
||||
|
||||
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Properties()))
|
||||
|
||||
private fun noSettingsItem(name: String): CobblemonItem = this.create(name, CobblemonItem(Item.Properties()))
|
||||
|
||||
@@ -54,6 +54,7 @@ import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.*
|
||||
import com.cobblemon.mod.common.net.PacketRegisterInfo
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
|
||||
@@ -74,6 +75,7 @@ import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
|
||||
@@ -85,7 +87,6 @@ import com.cobblemon.mod.common.net.messages.client.spawn.SpawnNPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.RemoveClientPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.SwapClientPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePartyPacket
|
||||
@@ -94,10 +95,13 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemo
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.*
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.*
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
|
||||
@@ -110,6 +114,7 @@ import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
@@ -125,7 +130,10 @@ import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonT
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.SwapPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.UnlinkPlayerFromPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSelectedHandler
|
||||
@@ -139,6 +147,8 @@ import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
|
||||
@@ -156,21 +166,6 @@ import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePartyPokemonTo
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.ReleasePartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.SwapPCPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.UnlinkPlayerFromPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.*
|
||||
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.*
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@@ -308,6 +303,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PokedexDexSyncPacket.ID, PokedexDexSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(DexEntrySyncPacket.ID, DexEntrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FishingBaitRegistrySyncPacket.ID, FishingBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
// Effects
|
||||
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
|
||||
|
||||
@@ -260,6 +260,10 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
|
||||
@JvmField
|
||||
val MOVE_QUICKATTACK_TARGET = this.create("move.quickattack.target")
|
||||
@JvmField
|
||||
val MOVE_PURSUIT_TARGET = this.create("move.pursuit.target")
|
||||
@JvmField
|
||||
val MOVE_PSYCHIC_TARGET = this.create("move.psychic.target")
|
||||
|
||||
@JvmField
|
||||
val IMPACT_NORMAL = this.create("impact.normal")
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.ai.LookInDirectionTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class LookInDirectionTaskConfig : SingleTaskConfig {
|
||||
var yaw: Expression = "0".asExpression()
|
||||
var pitch: Expression = "0".asExpression()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
) = LookInDirectionTask(yaw, pitch)
|
||||
}
|
||||
@@ -172,4 +172,15 @@ The 'flee_attacker' type creates a task that will make the entity flee from its
|
||||
The 'flee_nearest_hostile' type creates a task that will make the entity flee from the nearest hostile entity when it is hurt.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if this entire task should exist on the entity or not. This runs at the time of entity creation, not on tick.
|
||||
- `speedMultiplier`: A MoLang expression that determines the speed multiplier for fleeing from the nearest hostile. Defaults to 0.5 which is an elevated speed to usual.
|
||||
- `desiredDistance`: A MoLang expression that determines the distance from the nearest hostile that the entity should try to maintain. Defaults to 9.
|
||||
- `desiredDistance`: A MoLang expression that determines the distance from the nearest hostile that the entity should try to maintain. Defaults to 9.
|
||||
|
||||
### run_script
|
||||
The 'run_script' type creates a task that will run a MoLang script every tick on this entity. This has the risk of being very laggy
|
||||
if the script is doing expensive things. Remember to use `q.entity.world.game_time` and `math.mod` to do intermittent actions inside
|
||||
the script to avoid lagging the game.
|
||||
- `script`: A resource location identifying the script to run. This should be in the `molang` datapack folder.
|
||||
|
||||
### look_in_direction
|
||||
The 'look_in_direction' type creates a task that will make the entity look in a specific direction at all times where they aren't being told to look elsewhere.
|
||||
- `yaw`: A MoLang expression that determines the yaw angle (degrees) of the entity. Defaults to `0`.
|
||||
- `pitch`: A MoLang expression that determines the pitch angle (degrees) of the entity. Defaults to `0`.
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
/**
|
||||
* Runs a registered MoLang script (from the molang datapack folder) each tick.
|
||||
*
|
||||
* It's up to the user to not make expensive ass scripts. Remember you can access the game time
|
||||
* from q.entity.level.game_time which can be used with a modulo operator to make something intermittent.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 2nd, 2024
|
||||
*/
|
||||
class RunScript : SingleTaskConfig {
|
||||
val script = cobblemonResource("dummy")
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET) // I think I need to have at least something here?
|
||||
).apply(it) { _ ->
|
||||
Trigger { world, entity, _ ->
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: entity.asMostSpecificMoLangValue())
|
||||
return@Trigger CobblemonScripts.run(script, runtime) == DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,8 @@ fun interface TaskConfig {
|
||||
"calm_down" to CalmDownTaskConfig::class.java,
|
||||
"flee_attacker" to FleeAttackerTaskConfig::class.java,
|
||||
"flee_nearest_hostile" to FleeNearestHostileTaskConfig::class.java,
|
||||
"run_script" to RunScript::class.java,
|
||||
"look_in_direction" to LookInDirectionTaskConfig::class.java,
|
||||
)
|
||||
|
||||
val runtime = MoLangRuntime().setup()
|
||||
|
||||
@@ -94,7 +94,6 @@ open class PokemonBattle(
|
||||
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
|
||||
.forEach { it.reset() }
|
||||
}
|
||||
actor.setupStruct()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.battles.model.actor
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
|
||||
import com.cobblemon.mod.common.battles.ForcePassActionResponse
|
||||
@@ -36,7 +37,7 @@ abstract class BattleActor(
|
||||
pokemonList.forEach { it.actor = this }
|
||||
}
|
||||
|
||||
val struct = QueryStruct(hashMapOf())
|
||||
val struct = asMoLangValue()
|
||||
|
||||
lateinit var showdownId: String
|
||||
lateinit var battle: PokemonBattle
|
||||
@@ -139,10 +140,6 @@ abstract class BattleActor(
|
||||
battle.writeShowdownAction(">$showdownId ${showdownMessages.joinToString()}")
|
||||
}
|
||||
|
||||
open fun setupStruct() {
|
||||
struct.addFunction("uuid") { StringValue(uuid.toString()) }
|
||||
}
|
||||
|
||||
abstract fun getName(): MutableComponent
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
package com.cobblemon.mod.common.api.data
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.util.endsWith
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutionException
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
|
||||
@@ -42,7 +45,24 @@ interface JsonDataRegistry<T> : DataRegistry {
|
||||
val resourcePath: String
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
this.reload(Cobblemon.implementation.reloadJsonRegistry(this, manager))
|
||||
val data = hashMapOf<ResourceLocation, T>()
|
||||
manager.listResources(resourcePath) { path -> path.endsWith(JSON_EXTENSION) }.forEach { (identifier, resource) ->
|
||||
if (identifier.namespace == "pixelmon") {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
resource.open().use { stream ->
|
||||
stream.bufferedReader().use { reader ->
|
||||
val resolvedIdentifier = ResourceLocation.fromNamespaceAndPath(identifier.namespace, File(identifier.path).nameWithoutExtension)
|
||||
try {
|
||||
data[resolvedIdentifier] = gson.fromJson(reader, typeToken.type)
|
||||
} catch (exception: Exception) {
|
||||
throw ExecutionException("Error loading JSON for data: $identifier", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
reload(data)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,13 +21,13 @@ import com.cobblemon.mod.common.util.adapters.DialogueTextAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TextAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
/**
|
||||
@@ -56,7 +56,7 @@ object Dialogues : JsonDataRegistry<Dialogue> {
|
||||
.registerTypeAdapter(DialogueText::class.java, DialogueTextAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(MutableComponent::class.java, TextAdapter)
|
||||
.registerTypeAdapter(MutableComponent::class.java, TranslatedTextAdapter)
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.also { gsonObservable.emit(it) }
|
||||
.create()
|
||||
|
||||
+4
-4
@@ -19,8 +19,8 @@ import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
* @author Segfault Guy
|
||||
* @since April 6th, 2023
|
||||
*/
|
||||
data class BattleFaintedEvent (
|
||||
override val battle: PokemonBattle,
|
||||
val killed: BattlePokemon,
|
||||
val context: BattleContext
|
||||
data class BattleFaintedEvent(
|
||||
override val battle: PokemonBattle,
|
||||
val killed: BattlePokemon,
|
||||
val context: BattleContext
|
||||
) : BattleEvent
|
||||
|
||||
@@ -18,8 +18,6 @@ import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
* @since March 25th 2023
|
||||
*/
|
||||
data class BattleFledEvent (
|
||||
|
||||
override val battle: PokemonBattle,
|
||||
val player: PlayerBattleActor
|
||||
|
||||
) : BattleEvent
|
||||
+23
-1
@@ -8,8 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.battles
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
|
||||
import com.cobblemon.mod.common.util.asArrayValue
|
||||
|
||||
/**
|
||||
* Event fired when a battle is won by some number of [BattleActor]s.
|
||||
@@ -22,4 +28,20 @@ data class BattleVictoryEvent (
|
||||
val winners : List<BattleActor>,
|
||||
val losers : List<BattleActor>,
|
||||
val wasWildCapture : Boolean
|
||||
) : BattleEvent
|
||||
) : BattleEvent {
|
||||
val context = mutableMapOf<String, MoValue>(
|
||||
"battle" to battle.struct,
|
||||
"winners" to winners.asArrayValue { it.struct },
|
||||
"losers" to losers.asArrayValue { it.struct },
|
||||
"was_wild_capture" to DoubleValue(wasWildCapture),
|
||||
"player_winners" to winners.filter { it.type == ActorType.PLAYER }.asArrayValue { it.struct },
|
||||
"player_losers" to losers.filter { it.type == ActorType.PLAYER }.asArrayValue { it.struct },
|
||||
"npc_winners" to winners.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
|
||||
"npc_losers" to losers.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
|
||||
"wild_pokemon_winners" to winners.filter { it.type == ActorType.WILD }.asArrayValue { it.struct },
|
||||
"wild_pokemon_losers" to losers.filter { it.type == ActorType.WILD }.asArrayValue { it.struct },
|
||||
"players" to battle.actors.filter { it.type == ActorType.PLAYER }.asArrayValue { it.struct },
|
||||
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
|
||||
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct }
|
||||
)
|
||||
}
|
||||
+12
-1
@@ -8,12 +8,23 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
data class PokemonCapturedEvent (
|
||||
val pokemon: Pokemon,
|
||||
val player: ServerPlayer,
|
||||
val pokeBallEntity: EmptyPokeBallEntity
|
||||
)
|
||||
) {
|
||||
val context = mutableMapOf<String, MoValue>(
|
||||
"pokemon" to pokemon.struct,
|
||||
"player" to player.asMoLangValue(),
|
||||
"poke_ball" to pokeBallEntity.struct,
|
||||
"item" to player.level().itemRegistry.wrapAsHolder(pokeBallEntity.pokeBall.item).asMoLangValue(Registries.ITEM)
|
||||
)
|
||||
}
|
||||
@@ -24,7 +24,7 @@ abstract class ParentWidget(
|
||||
component: Component
|
||||
): Renderable, AbstractWidget(pX, pY, pWidth, pHeight, component) {
|
||||
|
||||
private val children: MutableList<GuiEventListener> = mutableListOf()
|
||||
val children: MutableList<GuiEventListener> = mutableListOf()
|
||||
|
||||
/**
|
||||
* Adds Widget to the children list
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.api.dialogue.ReferenceDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
@@ -37,17 +39,23 @@ import com.cobblemon.mod.common.api.storage.pc.PCPosition
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonMoveControl
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.mojang.datafixers.util.Either
|
||||
import java.util.UUID
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.commands.arguments.EntityAnchorArgument
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
@@ -59,14 +67,23 @@ import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.damagesource.DamageTypes
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.entity.LightningBolt
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.Level.ExplosionInteraction
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.dimension.DimensionType
|
||||
@@ -81,6 +98,25 @@ import net.minecraft.world.phys.Vec3
|
||||
*/
|
||||
object MoLangFunctions {
|
||||
val generalFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>(
|
||||
"print" to java.util.function.Function { params ->
|
||||
val message = params.get<MoValue>(0).asString()
|
||||
Cobblemon.LOGGER.info(message)
|
||||
},
|
||||
"replace" to java.util.function.Function { params ->
|
||||
val text = params.getString(0)
|
||||
val search = params.getString(1)
|
||||
val replace = params.getString(2)
|
||||
return@Function StringValue(text.replace(search, replace))
|
||||
},
|
||||
"is_blank" to java.util.function.Function { params ->
|
||||
val arg = params.get<MoValue>(0)
|
||||
return@Function DoubleValue((arg is StringValue && (arg.value.isBlank() || arg.value.toDoubleOrNull() == 0.0)) || (arg is DoubleValue && arg.value == 0.0))
|
||||
},
|
||||
"run_command" to java.util.function.Function { params ->
|
||||
val command = params.getString(0)
|
||||
val server = server() ?: return@Function DoubleValue.ZERO
|
||||
server.commands.performPrefixedCommand(server.createCommandSourceStack(), command)
|
||||
},
|
||||
"is_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().isInt()) },
|
||||
"is_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() != null) },
|
||||
"to_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() ?: 0.0) },
|
||||
@@ -115,19 +151,93 @@ object MoLangFunctions {
|
||||
runtime.environment.variable = params.environment.variable
|
||||
runtime.environment.context = params.environment.context
|
||||
val script = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
CobblemonScripts.run(script, runtime) ?: DoubleValue(0)
|
||||
CobblemonScripts.run(script, runtime) ?: DoubleValue.ZERO
|
||||
},
|
||||
"run_command" to java.util.function.Function { params ->
|
||||
val command = params.getString(0)
|
||||
server()?.let {
|
||||
return@Function DoubleValue(it.commands.dispatcher.execute(command, it.createCommandSourceStack()))
|
||||
} ?: return@Function DoubleValue.ZERO
|
||||
"run_molang" to java.util.function.Function { params ->
|
||||
val runtime = MoLangRuntime()
|
||||
runtime.environment.query = params.environment.query
|
||||
runtime.environment.variable = params.environment.variable
|
||||
runtime.environment.context = params.environment.context
|
||||
val expression = params.getString(0).asExpressionLike()
|
||||
runtime.resolve(expression)
|
||||
},
|
||||
)
|
||||
val biomeFunctions = mutableListOf<(Holder<Biome>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>()
|
||||
val worldFunctions = mutableListOf<(Holder<Level>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ worldHolder ->
|
||||
val world = worldHolder.value()
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("game_time") { _ -> DoubleValue(world.gameTime.toDouble()) }
|
||||
map.put("time_of_day") {
|
||||
val time = world.dayTime % 24000
|
||||
return@put DoubleValue(time.toDouble())
|
||||
}
|
||||
map.put("server") { _ -> server()?.asMoLangValue() ?: DoubleValue.ZERO }
|
||||
map.put("is_raining_at") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
val z = params.getInt(2)
|
||||
return@put DoubleValue(world.isRainingAt(BlockPos(x, y, z)))
|
||||
}
|
||||
map.put("is_chunk_loaded_at") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
val z = params.getInt(2)
|
||||
return@put DoubleValue(world.isLoaded(BlockPos(x, y, z)))
|
||||
}
|
||||
map.put("is_thundering") { _ -> DoubleValue(world.isThundering) }
|
||||
map.put("is_raining") { _ -> DoubleValue(world.isRaining) }
|
||||
map.put("set_block") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
val z = params.getInt(2)
|
||||
val block = world.blockRegistry.get(params.getString(3).asIdentifierDefaultingNamespace())
|
||||
?: run {
|
||||
Cobblemon.LOGGER.error("Unknown block: ${params.getString(3)}")
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
world.setBlock(BlockPos(x, y, z), block.defaultBlockState(), Block.UPDATE_ALL)
|
||||
}
|
||||
map.put("get_block") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
val z = params.getInt(2)
|
||||
val block = world.getBlockState(BlockPos(x, y, z)).block
|
||||
return@put world.blockRegistry.wrapAsHolder(block).asMoLangValue(Registries.BLOCK)
|
||||
}
|
||||
map.put("spawn_explosion") { params ->
|
||||
val x = params.getDouble(0)
|
||||
val y = params.getDouble(1)
|
||||
val z = params.getDouble(2)
|
||||
val range = params.getDouble(3).toFloat()
|
||||
world.explode(null, x, y, z, range, ExplosionInteraction.valueOf(params.getStringOrNull(4)?.uppercase() ?: ExplosionInteraction.TNT.name))
|
||||
}
|
||||
map.put("spawn_lightning") { params ->
|
||||
val x = params.getDouble(0)
|
||||
val y = params.getDouble(1)
|
||||
val z = params.getDouble(2)
|
||||
val lightning = LightningBolt(EntityType.LIGHTNING_BOLT, world)
|
||||
lightning.setPos(x, y, z)
|
||||
world.addFreshEntity(lightning)
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("get_entities_around") { params ->
|
||||
val x = params.getDouble(0)
|
||||
val y = params.getDouble(1)
|
||||
val z = params.getDouble(2)
|
||||
val range = params.getDouble(3) * 2
|
||||
val entities = world.getEntities(null, AABB.ofSize(Vec3(x, y, z), range, range, range))
|
||||
return@put entities
|
||||
.filterIsInstance<LivingEntity>()
|
||||
.map { it.asMostSpecificMoLangValue() }
|
||||
.asArrayValue()
|
||||
}
|
||||
|
||||
return@mutableListOf map
|
||||
}
|
||||
)
|
||||
val biomeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val worldFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val dimensionTypeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val blockFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val dimensionTypeFunctions = mutableListOf<(Holder<DimensionType>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>()
|
||||
val blockFunctions = mutableListOf<(Holder<Block>) -> HashMap<String, java.util.function.Function<MoParams, Any>>>()
|
||||
val playerFunctions = mutableListOf<(Player) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ player ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
@@ -141,7 +251,7 @@ object MoLangFunctions {
|
||||
map.put("saturation_level") { _ -> DoubleValue(player.foodData.saturationLevel) }
|
||||
map.put("tell") { params ->
|
||||
val message = params.getString(0).text()
|
||||
val overlay = params.getBooleanOrNull(1) ?: false
|
||||
val overlay = params.getBooleanOrNull(1) == true
|
||||
player.displayClientMessage(message, overlay)
|
||||
}
|
||||
map.put("teleport") { params ->
|
||||
@@ -160,7 +270,12 @@ object MoLangFunctions {
|
||||
environment.query = player.asMoLangValue()
|
||||
environment
|
||||
}
|
||||
map.put("is_player") { DoubleValue.ONE }
|
||||
if (player is ServerPlayer) {
|
||||
map.put("run_command") { params ->
|
||||
val command = params.getString(0)
|
||||
player.server.commands.performPrefixedCommand(player.createCommandSourceStack(), command)
|
||||
}
|
||||
map.put("is_party_at_full_health") { _ ->
|
||||
DoubleValue(player.party().none(Pokemon::canBeHealed)) }
|
||||
map.put("can_heal_at_healer") { params ->
|
||||
@@ -188,11 +303,46 @@ object MoLangFunctions {
|
||||
map.put("save_data") { _ -> Cobblemon.molangData.save(player.uuid) }
|
||||
map.put("in_battle") { DoubleValue(player.isInBattle()) }
|
||||
map.put("battle") { player.getBattleState()?.first?.struct ?: DoubleValue.ZERO }
|
||||
map.put("get_npc_data") { params ->
|
||||
val npcId = (params.get<MoValue>(0) as? ObjectValue<NPCEntity>)?.obj?.stringUUID ?: params.getString(0)
|
||||
val data = Cobblemon.molangData.load(player.uuid)
|
||||
if (data.map.containsKey(npcId)) {
|
||||
return@put data.map[npcId]!!
|
||||
} else {
|
||||
val vars = VariableStruct()
|
||||
data.map[npcId] = vars
|
||||
return@put vars
|
||||
}
|
||||
}
|
||||
map.put("get_npc_variable") { params ->
|
||||
val npcId = (params.get<MoValue>(0) as? ObjectValue<NPCEntity>)?.obj?.stringUUID ?: params.getString(0)
|
||||
val variable = params.getString(1)
|
||||
val data = Cobblemon.molangData.load(player.uuid)
|
||||
if (data.map.containsKey(npcId)) {
|
||||
return@put (data.map[npcId] as VariableStruct).map[variable] ?: DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("set_npc_variable") { params ->
|
||||
val npcId = (params.get<MoValue>(0) as? ObjectValue<NPCEntity>)?.obj?.stringUUID ?: params.getString(0)
|
||||
val variable = params.getString(1)
|
||||
val value = params.get<MoValue>(2)
|
||||
val saveAfterwards = params.getBooleanOrNull(3) != false
|
||||
val data = Cobblemon.molangData.load(player.uuid)
|
||||
if (data.map.containsKey(npcId)) {
|
||||
(data.map[npcId] as VariableStruct).map[variable] = value
|
||||
if (saveAfterwards) {
|
||||
Cobblemon.molangData.save(player.uuid)
|
||||
}
|
||||
return@put DoubleValue.ONE
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
)
|
||||
val entityFunctions = mutableListOf<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
val entityFunctions: MutableList<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ entity ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("uuid") { _ -> StringValue(entity.uuid.toString()) }
|
||||
@@ -201,6 +351,28 @@ object MoLangFunctions {
|
||||
val source = DamageSource(entity.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolder(DamageTypes.GENERIC).get())
|
||||
entity.hurt(source, amount.toFloat())
|
||||
}
|
||||
map.put("walk_to") { params ->
|
||||
val x = params.getDouble(0)
|
||||
val y = params.getDouble(1)
|
||||
val z = params.getDouble(2)
|
||||
val speedMultiplier = params.getDoubleOrNull(3) ?: 0.35
|
||||
if (entity is PathfinderMob) {
|
||||
if (entity.brain.checkMemory(MemoryModuleType.WALK_TARGET, MemoryStatus.REGISTERED)) {
|
||||
entity.brain.setMemory(MemoryModuleType.WALK_TARGET, WalkTarget(Vec3(x, y, z), speedMultiplier.toFloat(), 1))
|
||||
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET, BlockPosTracker(Vec3(x, y + entity.eyeHeight, z)))
|
||||
} else {
|
||||
entity.navigation.moveTo(x, y, z, speedMultiplier)
|
||||
entity.lookControl.setLookAt(Vec3(x, y + entity.eyeHeight, z))
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put("has_walk_target") { _ ->
|
||||
if (entity is PathfinderMob) {
|
||||
DoubleValue(entity.brain.getMemory(MemoryModuleType.WALK_TARGET).isPresent || entity.isPathFinding)
|
||||
} else {
|
||||
DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("is_sneaking") { _ -> DoubleValue(entity.isShiftKeyDown) }
|
||||
map.put("is_sprinting") { _ -> DoubleValue(entity.isSprinting) }
|
||||
map.put("is_flying") { _ -> DoubleValue(entity.isFallFlying) }
|
||||
@@ -212,8 +384,14 @@ object MoLangFunctions {
|
||||
map.put("is_on_fire") { _ -> DoubleValue(entity.isOnFire) }
|
||||
map.put("is_invisible") { _ -> DoubleValue(entity.isInvisible) }
|
||||
map.put("is_sleeping") { _ -> DoubleValue(entity.isSleeping) }
|
||||
map.put("is_riding") { _ -> DoubleValue(entity.isPassenger()) }
|
||||
map.put("is_riding") { _ -> DoubleValue(entity.isPassenger) }
|
||||
map.put("health") { _ -> DoubleValue(entity.health) }
|
||||
map.put("distance_to_pos") { params ->
|
||||
val x = params.getDouble(0)
|
||||
val y = params.getDouble(1)
|
||||
val z = params.getDouble(2)
|
||||
return@put DoubleValue(sqrt(entity.distanceToSqr(Vec3(x, y, z))))
|
||||
}
|
||||
map.put("max_health") { _ -> DoubleValue(entity.maxHealth) }
|
||||
map.put("name") { _ -> StringValue(entity.effectiveName().string) }
|
||||
map.put("yaw") { _ -> DoubleValue(entity.yRot.toDouble()) }
|
||||
@@ -255,6 +433,21 @@ object MoLangFunctions {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("get_nearby_entities") { params ->
|
||||
val distance = params.getDouble(0)
|
||||
val entities = entity.level().getEntities(entity, AABB.ofSize(entity.position(), distance, distance, distance))
|
||||
return@put entities
|
||||
.filterIsInstance<LivingEntity>()
|
||||
.map { it.asMostSpecificMoLangValue() }
|
||||
.asArrayValue()
|
||||
}
|
||||
if (entity is PosableEntity) {
|
||||
map.put("play_animation") { params ->
|
||||
val animation = params.getString(0)
|
||||
val packet = PlayPosableAnimationPacket(entity.id, setOf(animation), emptyList())
|
||||
packet.sendToPlayersAround(entity.x, entity.y, entity.z, 64.0, entity.level().dimension())
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
)
|
||||
@@ -315,9 +508,9 @@ object MoLangFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
return@put DoubleValue(1)
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
return@put DoubleValue(0)
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
map.put("put_pokemon_in_healer") { params ->
|
||||
val healer = npc.level().getBlockEntity(params.get<ArrayStruct>(0).asBlockPos(), CobblemonBlockEntities.HEALING_MACHINE).orElse(null) ?: return@put DoubleValue.ZERO
|
||||
@@ -336,6 +529,8 @@ object MoLangFunctions {
|
||||
map.put("environment") { _ -> npc.runtime.environment }
|
||||
map.put("party") { npc.party?.struct ?: DoubleValue.ZERO }
|
||||
map.put("has_party") { DoubleValue(npc.party != null) }
|
||||
map.put("is_npc") { DoubleValue.ONE }
|
||||
map.put("can_battle") { DoubleValue(npc.party?.any { it.currentHealth > 0 } == true || npc.npc.party?.isStatic == false) }
|
||||
map
|
||||
}
|
||||
)
|
||||
@@ -355,10 +550,26 @@ object MoLangFunctions {
|
||||
return@put actor.struct
|
||||
}
|
||||
map.put("stop") { _ -> battle.stop() }
|
||||
map.put("actors") { battle.actors.toList().asArrayValue { it.struct } }
|
||||
map
|
||||
}
|
||||
)
|
||||
|
||||
val battleActorFunctions = mutableListOf<(BattleActor) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ battleActor ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("is_npc") { DoubleValue(battleActor.type == ActorType.NPC) }
|
||||
map.put("is_player") { DoubleValue(battleActor.type == ActorType.PLAYER) }
|
||||
map.put("is_wild") { DoubleValue(battleActor.type == ActorType.WILD) }
|
||||
if (battleActor is NPCBattleActor) {
|
||||
map.put("npc") { battleActor.entity.struct }
|
||||
} else if (battleActor is PlayerBattleActor) {
|
||||
map.put("player") { battleActor.entity?.asMoLangValue() ?: DoubleValue.ZERO }
|
||||
}
|
||||
return@mutableListOf map
|
||||
}
|
||||
)
|
||||
|
||||
val pokemonFunctions = mutableListOf<(Pokemon) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ pokemon ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
@@ -397,6 +608,7 @@ object MoLangFunctions {
|
||||
map.put("is_moving") { DoubleValue((pokemonEntity.moveControl as? PokemonMoveControl)?.hasWanted() == true) }
|
||||
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
|
||||
map.put("has_aspect") { DoubleValue(it.getString(0) in pokemonEntity.aspects) }
|
||||
map.put("is_pokemon") { DoubleValue.ONE }
|
||||
map
|
||||
}
|
||||
)
|
||||
@@ -535,10 +747,68 @@ object MoLangFunctions {
|
||||
}
|
||||
)
|
||||
|
||||
fun Holder<Biome>.asBiomeMoLangValue() = asMoLangValue(Registries.BIOME).addFunctions(biomeFunctions)
|
||||
fun Holder<Level>.asWorldMoLangValue() = asMoLangValue(Registries.DIMENSION).addFunctions(worldFunctions)
|
||||
fun Holder<Block>.asBlockMoLangValue() = asMoLangValue(Registries.BLOCK).addFunctions(blockFunctions)
|
||||
fun Holder<DimensionType>.asDimensionTypeMoLangValue() = asMoLangValue(Registries.DIMENSION_TYPE).addFunctions(dimensionTypeFunctions)
|
||||
val serverFunctions: MutableList<(MinecraftServer) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
{ server ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
|
||||
map.put("get_world") { params ->
|
||||
val world = server.getLevel(
|
||||
ResourceKey.create(
|
||||
Registries.DIMENSION,
|
||||
params.getString(0).asIdentifierDefaultingNamespace(namespace = "minecraft")
|
||||
)
|
||||
) ?: return@put DoubleValue.ZERO
|
||||
|
||||
return@put world
|
||||
.registryAccess()
|
||||
.registryOrThrow(Registries.DIMENSION)
|
||||
.wrapAsHolder(world)
|
||||
.asWorldMoLangValue()
|
||||
}
|
||||
|
||||
map.put("broadcast") { params ->
|
||||
val message = params.getString(0)
|
||||
server.playerList.broadcastSystemMessage(message.text(), params.getBooleanOrNull(1) == true)
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
|
||||
map.put("get_player_by_uuid") { params ->
|
||||
val uuid = UUID.fromString(params.getString(0))
|
||||
val player = server.playerList.getPlayer(uuid) ?: return@put DoubleValue.ZERO
|
||||
return@put player.asMoLangValue()
|
||||
}
|
||||
|
||||
map.put("get_player_by_username") { params ->
|
||||
val username = params.getString(0)
|
||||
val player = server.playerList.getPlayerByName(username) ?: return@put DoubleValue.ZERO
|
||||
return@put player.asMoLangValue()
|
||||
}
|
||||
|
||||
map.put("data") { params ->
|
||||
val data = Cobblemon.molangData.load(UUID(0L, 0L))
|
||||
return@put data
|
||||
}
|
||||
|
||||
map.put("save_data") {
|
||||
Cobblemon.molangData.save(UUID(0L, 0L))
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
|
||||
// Maybe later...
|
||||
// map.put("stop") { params ->
|
||||
// Cobblemon.LOGGER.warn("Server is being stopped from a MoLang script.")
|
||||
// server.stopServer()
|
||||
// }
|
||||
|
||||
return@mutableListOf map
|
||||
}
|
||||
)
|
||||
|
||||
fun Holder<Biome>.asBiomeMoLangValue() = asMoLangValue(Registries.BIOME).addFunctions(biomeFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
fun Holder<Level>.asWorldMoLangValue() = asMoLangValue(Registries.DIMENSION).addFunctions(worldFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
fun Holder<Block>.asBlockMoLangValue() = asMoLangValue(Registries.BLOCK).addFunctions(blockFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
fun MinecraftServer.asMoLangValue() = ObjectValue(this).addStandardFunctions().addFunctions(serverFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
fun Holder<DimensionType>.asDimensionTypeMoLangValue() = asMoLangValue(Registries.DIMENSION_TYPE).addFunctions(dimensionTypeFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
fun Player.asMoLangValue(): ObjectValue<Player> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
@@ -586,6 +856,17 @@ object MoLangFunctions {
|
||||
return value
|
||||
}
|
||||
|
||||
fun PokemonEntity.asMoLangValue(): ObjectValue<PokemonEntity> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.pokemon.uuid.toString() }
|
||||
)
|
||||
value.addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
value.addFunctions(pokemonFunctions.flatMap { it(this.pokemon).entries.map { it.key to it.value } }.toMap()) // Convenience
|
||||
value.addFunctions(pokemonEntityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
}
|
||||
|
||||
fun PokemonBattle.asMoLangValue(): ObjectValue<PokemonBattle> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
@@ -595,6 +876,15 @@ object MoLangFunctions {
|
||||
return value
|
||||
}
|
||||
|
||||
fun BattleActor.asMoLangValue(): ObjectValue<BattleActor> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.toString() }
|
||||
)
|
||||
value.addFunctions(battleActorFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
}
|
||||
|
||||
fun SpawningContext.asMoLangValue(): ObjectValue<SpawningContext> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
@@ -604,6 +894,18 @@ object MoLangFunctions {
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Different functions exist depending on
|
||||
*/
|
||||
fun LivingEntity.asMostSpecificMoLangValue(): ObjectValue<out LivingEntity> {
|
||||
return when (this) {
|
||||
is Player -> asMoLangValue()
|
||||
is PokemonEntity -> struct
|
||||
is NPCEntity -> struct
|
||||
else -> ObjectValue(this).also { it.addStandardFunctions().addFunctions(entityFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap()) }
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Holder<T>.asMoLangValue(key: ResourceKey<Registry<T>>): ObjectValue<Holder<T>> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
|
||||
@@ -70,7 +70,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
.registerTypeAdapter(MoValue::class.java, MoValueAdapter)
|
||||
.registerTypeAdapter(NPCClass::class.java, NPCClassAdapter)
|
||||
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
|
||||
.registerTypeAdapter(Component::class.java, TextAdapter)
|
||||
.registerTypeAdapter(Component::class.java, TranslatedTextAdapter)
|
||||
.registerTypeAdapter(WeightedAspect::class.java, WeightedAspectAdapter)
|
||||
.registerTypeAdapter(BrainConfig::class.java, BrainConfigAdapter)
|
||||
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
package com.cobblemon.mod.common.api.npc
|
||||
|
||||
import com.cobblemon.mod.common.api.npc.partyproviders.PoolPartyProvider
|
||||
import com.cobblemon.mod.common.api.npc.partyproviders.ScriptPartyProvider
|
||||
import com.cobblemon.mod.common.api.npc.partyproviders.SimplePartyProvider
|
||||
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
/**
|
||||
* A provider of a party for battling the NPC. Completely custom party providers will only display
|
||||
@@ -25,13 +27,14 @@ interface NPCPartyProvider {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, (String) -> NPCPartyProvider>(
|
||||
SimplePartyProvider.TYPE to { SimplePartyProvider() },
|
||||
PoolPartyProvider.TYPE to { PoolPartyProvider() }
|
||||
PoolPartyProvider.TYPE to { PoolPartyProvider() },
|
||||
ScriptPartyProvider.TYPE to { ScriptPartyProvider() }
|
||||
)
|
||||
}
|
||||
|
||||
val type: String
|
||||
val isStatic: Boolean
|
||||
fun provide(npc: NPCEntity, level: Int): NPCPartyStore
|
||||
fun provide(npc: NPCEntity, level: Int, players: List<ServerPlayer> = emptyList()): NPCPartyStore
|
||||
// Why did I opt for manual JSON loading??? I must have had a reason but I can't remember. Maybe for S2C? Use a codec doofus
|
||||
fun loadFromJSON(json: JsonElement)
|
||||
}
|
||||
@@ -67,7 +67,7 @@ object NPCPresets : JsonDataRegistry<NPCPreset> {
|
||||
.registerTypeAdapter(NPCVariationProvider::class.java, NPCVariationProviderAdapter)
|
||||
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
|
||||
.registerTypeAdapter(MoValue::class.java, MoValueAdapter)
|
||||
.registerTypeAdapter(Component::class.java, TextAdapter)
|
||||
.registerTypeAdapter(Component::class.java, TranslatedTextAdapter)
|
||||
.registerTypeAdapter(BrainConfig::class.java, BrainConfigAdapter)
|
||||
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
|
||||
@@ -57,8 +57,8 @@ any number of presets and the properties of those presets will be merged into th
|
||||
"variableName": "challenge_distance",
|
||||
"displayName": "cobblemon.npc.challenge_distance",
|
||||
"description": "cobblemon.npc.challenge_distance.description",
|
||||
"type": "number",
|
||||
"default": "5"
|
||||
"type": "NUMBER",
|
||||
"defaultValue": "5"
|
||||
}
|
||||
],
|
||||
"names": [
|
||||
@@ -178,19 +178,19 @@ An example situation of using this is if there is an NPC class preset that defin
|
||||
challenging a player when they come within a certain range. Inside that class preset, the AI script may
|
||||
need to know at what distance the player will be engaged. This can be defined in the NPC class preset as
|
||||
a config variable, and therefore any NPC class that relies on this preset will have that config variable
|
||||
and present it to users when they setup an NPC of that class.
|
||||
and present it to users when they set up an NPC of that class.
|
||||
|
||||
"config": [
|
||||
{
|
||||
"variableName": "challenge_distance",
|
||||
"displayName": "cobblemon.npc.challenge_distance",
|
||||
"description": "cobblemon.npc.challenge_distance.description",
|
||||
"type": "number",
|
||||
"default": "5"
|
||||
"displayName": "cobblemon.npc.challenge_distance.name",
|
||||
"description": "cobblemon.npc.challenge_distance.desc",
|
||||
"type": "NUMBER",
|
||||
"defaultValue": "5"
|
||||
}
|
||||
]
|
||||
|
||||
The "type" of variable is one of: `string`, `number`, or `boolean`. The type is used to preset a more
|
||||
The "type" of variable is one of: `STRING`, `NUMBER`, or `BOOLEAN`. The type is used to preset a more
|
||||
appropriate input field for the user when they are setting up the NPC.
|
||||
|
||||
### names
|
||||
@@ -298,6 +298,10 @@ depend on visual aspects of the NPC. For example, if the NPC has a variation for
|
||||
certain Pokémon to be `"weight": "q.npc.has_aspect('dirty') ? -1 : 0"` which would make it a guaranteed party Pokémon for "dirty" NPCs
|
||||
and impossible for all other variations of the NPC.
|
||||
|
||||
The MoLang environment used for the pool party provider contains q.level for the seed level, q.npc for the NPC, as well as q.players for
|
||||
an array of all players that are challenging the NPC. The players list is only present for dynamic parties. If it is specifically
|
||||
a single battle challenge and this is a dynamic party, there will also be a `q.player`, for convenience.
|
||||
|
||||
"party": {
|
||||
"type": "pool",
|
||||
"minPokemon": "3",
|
||||
@@ -344,6 +348,33 @@ and impossible for all other variations of the NPC.
|
||||
]
|
||||
}
|
||||
|
||||
#### script
|
||||
The "script" party type is a way to define a party of Pokémon using a MoLang script. The script can modify a q.party struct,
|
||||
primarily using function calls such as `q.party.add_by_properties('pikachu shiny)`.
|
||||
|
||||
There is an `isStatic` property to control whether the party is static or dynamic. There is a `script` property which is a
|
||||
resource location pointing to the script that should be located in the `molang` datapack folder.
|
||||
|
||||
The MoLang environment used for the script party provider contains q.level for the seed level, q.npc for the NPC, as well as q.players for
|
||||
an array of all players that are challenging the NPC. The players list is only present for dynamic parties. If it is specifically
|
||||
a single battle challenge and this is a dynamic party, there will also be a `q.player`, for convenience.
|
||||
|
||||
"party": {
|
||||
"type": "script",
|
||||
"isStatic": true,
|
||||
"script": "cobblemon:npc_party"
|
||||
}
|
||||
|
||||
An example script might be:
|
||||
|
||||
t.use_butterfree = math.random_integer(1, 2) == 1;
|
||||
t.use_butterfree ? {
|
||||
q.party.add_by_properties('butterfree level=' + (q.level + 3));
|
||||
} : {
|
||||
q.party.add_by_properties('beedrill level=' + (q.level + 3));
|
||||
};
|
||||
q.party.add_by_properties('pidgey');
|
||||
|
||||
### autoHealParty
|
||||
Whether or not the NPC's party will be healed between battles. If the NPC has a dynamic party, this option will
|
||||
do nothing. If the NPC has a static party and this option is false, their Pokémon will not be healed and the
|
||||
|
||||
+36
-8
@@ -13,6 +13,11 @@ import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.readText
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import com.cobblemon.mod.common.util.writeText
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
/**
|
||||
@@ -30,10 +35,38 @@ class NPCConfigVariable(
|
||||
val type: NPCVariableType = NPCVariableType.NUMBER,
|
||||
val defaultValue: String = "0",
|
||||
) {
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): NPCConfigVariable {
|
||||
return NPCConfigVariable(
|
||||
buffer.readString(),
|
||||
buffer.readText(),
|
||||
buffer.readText(),
|
||||
buffer.readEnum(NPCVariableType::class.java),
|
||||
buffer.readString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
enum class NPCVariableType {
|
||||
NUMBER,
|
||||
STRING,
|
||||
BOOLEAN
|
||||
TEXT,
|
||||
BOOLEAN;
|
||||
|
||||
fun toMoValue(value: String): MoValue {
|
||||
return when (this) {
|
||||
TEXT -> StringValue(value)
|
||||
BOOLEAN -> DoubleValue(value.let { it == "1" || it.toBooleanStrictOrNull() == true })
|
||||
else -> DoubleValue(value.toDouble())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeString(variableName)
|
||||
buffer.writeText(displayName)
|
||||
buffer.writeText(description)
|
||||
buffer.writeEnum(type)
|
||||
buffer.writeString(defaultValue)
|
||||
}
|
||||
|
||||
fun apply(npc: NPCEntity, value: MoValue) {
|
||||
@@ -41,11 +74,6 @@ class NPCConfigVariable(
|
||||
}
|
||||
|
||||
fun applyDefault(npc: NPCEntity) {
|
||||
val value = when (type) {
|
||||
NPCVariableType.STRING -> StringValue(defaultValue)
|
||||
NPCVariableType.BOOLEAN -> DoubleValue(defaultValue.toBoolean())
|
||||
else -> DoubleValue(defaultValue.toDouble())
|
||||
}
|
||||
npc.config.set(variableName.split(".").iterator(), value)
|
||||
npc.config.setDirectly(variableName, type.toMoValue(defaultValue))
|
||||
}
|
||||
}
|
||||
+15
-5
@@ -10,11 +10,14 @@ package com.cobblemon.mod.common.api.npc.partyproviders
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.npc.NPCPartyProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.asArrayValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
@@ -23,6 +26,7 @@ import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
/**
|
||||
* A provider of a party for battling the NPC. It generates a party using a more complex process
|
||||
@@ -93,16 +97,22 @@ class PoolPartyProvider : NPCPartyProvider {
|
||||
}
|
||||
}
|
||||
|
||||
fun formulateParty(npc: NPCEntity, level: Int, party: NPCPartyStore) {
|
||||
fun formulateParty(npc: NPCEntity, level: Int, players: List<ServerPlayer>, party: NPCPartyStore) {
|
||||
val runtime = MoLangRuntime().setup().withQueryValue("npc", npc.struct)
|
||||
runtime.withQueryValue("level", DoubleValue(level))
|
||||
runtime.withQueryValue("players", players.asArrayValue { it.asMoLangValue() })
|
||||
if (players.size == 1) {
|
||||
// This is for the convenience, most cases will be pvn one player
|
||||
runtime.withQueryValue("player", players.first().asMoLangValue())
|
||||
}
|
||||
val minPokemon = runtime.resolveInt(this.minPokemon)
|
||||
val maxPokemon = runtime.resolveInt(this.maxPokemon)
|
||||
var desiredPokemonCount = (minPokemon..maxPokemon).random()
|
||||
|
||||
val workingPool = pool.filter { level in it.npcLevels }.toMutableList()
|
||||
val workingPool = pool.filter { level in it.npcLevels && runtime.resolveInt(it.selectableTimes) > 0 }.toMutableList()
|
||||
val useCounts = mutableMapOf<DynamicPokemon, Int>()
|
||||
|
||||
while (desiredPokemonCount > 0 && workingPool.filter { it.hasWeight(runtime) }.isNotEmpty()) {
|
||||
while (desiredPokemonCount > 0 && workingPool.any { it.hasWeight(runtime) }) {
|
||||
val selected = workingPool.filter { it.getWeight(runtime) == -1F }.randomOrNull()
|
||||
?: workingPool.weightedSelection { it.getWeight(runtime) }
|
||||
?: break
|
||||
@@ -121,9 +131,9 @@ class PoolPartyProvider : NPCPartyProvider {
|
||||
}
|
||||
}
|
||||
|
||||
override fun provide(npc: NPCEntity, level: Int): NPCPartyStore {
|
||||
override fun provide(npc: NPCEntity, level: Int, players: List<ServerPlayer>): NPCPartyStore {
|
||||
val party = NPCPartyStore(npc)
|
||||
formulateParty(npc, level, party)
|
||||
formulateParty(npc, level, players, party)
|
||||
return party
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.npc.partyproviders
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.npc.NPCPartyProvider
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.asArrayValue
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.toProperties
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
class ScriptPartyProvider : NPCPartyProvider {
|
||||
companion object {
|
||||
const val TYPE = "script"
|
||||
}
|
||||
|
||||
override val type = TYPE
|
||||
override var isStatic: Boolean = true
|
||||
var script: ResourceLocation = cobblemonResource("dummy")
|
||||
|
||||
override fun loadFromJSON(json: JsonElement) {
|
||||
isStatic = json.asJsonObject.get("isStatic")?.asBoolean != false
|
||||
script = json.asJsonObject.get("script").asString.asIdentifierDefaultingNamespace()
|
||||
}
|
||||
|
||||
override fun provide(npc: NPCEntity, level: Int, players: List<ServerPlayer>): NPCPartyStore {
|
||||
val runtime = MoLangRuntime().setup().withQueryValue("npc", npc.struct)
|
||||
runtime.withQueryValue("level", DoubleValue(level))
|
||||
runtime.withQueryValue("players", players.asArrayValue { it.asMoLangValue() })
|
||||
if (players.size == 1) {
|
||||
// This is for the convenience, most cases will be pvn one player
|
||||
runtime.withQueryValue("player", players.first().asMoLangValue())
|
||||
}
|
||||
val npcParty = NPCPartyStore(npc)
|
||||
runtime.withQueryValue("party", npcParty.struct)
|
||||
|
||||
if (!CobblemonScripts.scripts.containsKey(script)) {
|
||||
Cobblemon.LOGGER.error("Script $script not found in script registry.")
|
||||
npcParty.add("magikarp".toProperties().create())
|
||||
return npcParty
|
||||
}
|
||||
|
||||
CobblemonScripts.run(identifier = script, runtime = runtime)
|
||||
|
||||
return npcParty
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.storage.party.NPCPartyStore
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.toProperties
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
/**
|
||||
* A basic party provider that just produces a [NPCPartyStore] based on a simple list of [PokemonProperties].
|
||||
@@ -52,7 +53,7 @@ class SimplePartyProvider : NPCPartyProvider {
|
||||
}
|
||||
}
|
||||
|
||||
override fun provide(npc: NPCEntity, level: Int): NPCPartyStore {
|
||||
override fun provide(npc: NPCEntity, level: Int, players: List<ServerPlayer>): NPCPartyStore {
|
||||
val pokemon = pokemon.map { it.copy().also { it.level = it.level ?: level }.create() }
|
||||
val party = NPCPartyStore(npc)
|
||||
pokemon.forEach(party::add)
|
||||
|
||||
@@ -36,7 +36,7 @@ import com.cobblemon.mod.common.pokemon.RenderablePokemon
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.isInt
|
||||
import com.cobblemon.mod.common.util.isDouble
|
||||
import com.cobblemon.mod.common.util.isUuid
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.util.simplify
|
||||
@@ -59,7 +59,6 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
|
||||
@@ -187,10 +186,10 @@ open class PokemonProperties {
|
||||
private fun parseIntProperty(keyPairs: MutableList<Pair<String, String?>>, labels: Iterable<String>): Int? {
|
||||
val matchingKeyPair = getMatchedKeyPair(keyPairs, labels) ?: return null
|
||||
val value = matchingKeyPair.second
|
||||
return if (value == null || !value.isInt()) {
|
||||
return if (value == null || !value.isDouble()) {
|
||||
null
|
||||
} else {
|
||||
value.toInt()
|
||||
value.toDouble().toInt()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,7 +789,7 @@ open class PokemonProperties {
|
||||
}
|
||||
|
||||
fun copy(): PokemonProperties {
|
||||
return PokemonProperties().loadFromJSON(saveToJSON())
|
||||
return PokemonProperties().loadFromJSON(this.saveToJSON())
|
||||
}
|
||||
|
||||
// If the config value is at least 1, then do 1/x and use that as the property chance
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.ScriptRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.contextOrEmpty
|
||||
import com.cobblemon.mod.common.util.endsWith
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@@ -64,6 +65,6 @@ object CobblemonScripts : DataRegistry {
|
||||
}
|
||||
|
||||
fun run(identifier: ResourceLocation, runtime: MoLangRuntime): MoValue? {
|
||||
return scripts[identifier]?.resolve(runtime)
|
||||
return scripts[identifier]?.resolve(runtime, runtime.contextOrEmpty)
|
||||
}
|
||||
}
|
||||
@@ -315,7 +315,7 @@ object BattleBuilder {
|
||||
): BattleStartResult {
|
||||
val playerTeam = party.toBattleTeam(clone = cloneParties, healPokemon = healFirst, leadingPokemon = leadingPokemon)
|
||||
val playerActor = PlayerBattleActor(player.uuid, playerTeam)
|
||||
val npcParty = npcEntity.getPartyForChallenge(player)
|
||||
val npcParty = npcEntity.getPartyForChallenge(listOf(player))
|
||||
val errors = ErroredBattleStart()
|
||||
|
||||
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.npc
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.gui.npc.widgets.ConfigVariableList
|
||||
import com.cobblemon.mod.common.client.gui.npc.widgets.NPCRenderWidget
|
||||
import com.cobblemon.mod.common.client.gui.npc.widgets.SimpleNPCTextInputWidget
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.dto.NPCConfigurationDTO
|
||||
@@ -27,8 +27,6 @@ class NPCEditorScreen(
|
||||
companion object {
|
||||
const val BASE_WIDTH = 331
|
||||
const val BASE_HEIGHT = 161
|
||||
|
||||
private val baseResource = cobblemonResource("textures/gui/npc/editor_base.png")
|
||||
}
|
||||
|
||||
val middleX: Int
|
||||
@@ -43,13 +41,13 @@ class NPCEditorScreen(
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
addRenderableOnly(NPCRenderWidget(leftX + 6, topY + 32, dto.npcClass, dto.aspects))
|
||||
addRenderableOnly(NPCRenderWidget(leftX + 6, topY + 22, dto.npcClass, dto.aspects))
|
||||
addRenderableWidget(SimpleNPCTextInputWidget(
|
||||
texture = cobblemonResource("textures/gui/npc/basic_text_input.png"),
|
||||
getter = { dto.npcName.string },
|
||||
setter = { dto.npcName = it.text() },
|
||||
x = leftX + 79,
|
||||
y = topY + 14,
|
||||
x = leftX + 6,
|
||||
y = topY + 80,
|
||||
width = 130,
|
||||
height = 22
|
||||
))
|
||||
@@ -60,8 +58,8 @@ class NPCEditorScreen(
|
||||
dto.aspects.clear()
|
||||
dto.aspects.addAll(it.split(",").map { it.trim() })
|
||||
},
|
||||
x = leftX + 79,
|
||||
y = topY + 36,
|
||||
x = leftX + 6,
|
||||
y = topY + 100,
|
||||
width = 130,
|
||||
height = 40,
|
||||
maxLength = 75,
|
||||
@@ -73,21 +71,23 @@ class NPCEditorScreen(
|
||||
SaveNPCPacket(npcId, dto).sendToServer()
|
||||
this.minecraft!!.setScreen(null)
|
||||
}
|
||||
.pos(leftX + BASE_WIDTH - 42, topY + BASE_HEIGHT - 18)
|
||||
.pos(leftX + BASE_WIDTH - 42, topY + BASE_HEIGHT - 8)
|
||||
.size(40, 16)
|
||||
.build()
|
||||
)
|
||||
|
||||
addRenderableWidget(ConfigVariableList(leftX + 200, topY + 30, this))
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
texture = baseResource,
|
||||
x = leftX,
|
||||
y = topY,
|
||||
height = BASE_HEIGHT,
|
||||
width = BASE_WIDTH
|
||||
)
|
||||
// blitk(
|
||||
// matrixStack = context.pose(),
|
||||
// texture = baseResource,
|
||||
// x = leftX,
|
||||
// y = topY,
|
||||
// height = BASE_HEIGHT,
|
||||
// width = BASE_WIDTH
|
||||
// )
|
||||
super.render(context, mouseX, mouseY, delta)
|
||||
}
|
||||
}
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.gui.npc.widgets
|
||||
|
||||
import com.cobblemon.mod.common.api.npc.NPCClasses
|
||||
import com.cobblemon.mod.common.api.npc.configuration.NPCConfigVariable
|
||||
import com.cobblemon.mod.common.api.npc.configuration.NPCConfigVariable.NPCVariableType
|
||||
import com.cobblemon.mod.common.client.gui.npc.NPCEditorScreen
|
||||
import com.cobblemon.mod.common.client.gui.npc.widgets.ConfigVariableList.ConfigVariable
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.ContainerObjectSelectionList
|
||||
import net.minecraft.client.gui.components.CycleButton
|
||||
import net.minecraft.client.gui.components.EditBox
|
||||
import net.minecraft.client.gui.components.Tooltip
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener
|
||||
import net.minecraft.client.gui.narration.NarratableEntry
|
||||
|
||||
class ConfigVariableList(
|
||||
val listX: Int,
|
||||
val listY: Int,
|
||||
val parent: NPCEditorScreen
|
||||
) : ContainerObjectSelectionList<ConfigVariable>(
|
||||
Minecraft.getInstance(),
|
||||
WIDTH, // width
|
||||
HEIGHT, // height
|
||||
0, // top
|
||||
SLOT_HEIGHT + SLOT_SPACING
|
||||
) {
|
||||
companion object {
|
||||
const val WIDTH = 200
|
||||
const val HEIGHT = 120
|
||||
const val SLOT_WIDTH = 160
|
||||
const val SLOT_HEIGHT = 33
|
||||
const val SLOT_SPACING = 0
|
||||
}
|
||||
|
||||
private var scrolling = false
|
||||
|
||||
override fun getRowWidth() = SLOT_WIDTH
|
||||
|
||||
init {
|
||||
this.x = listX
|
||||
this.y = listY
|
||||
correctSize()
|
||||
setRenderHeader(false, 0)
|
||||
val npcClass = NPCClasses.getByIdentifier(parent.dto.npcClass)
|
||||
if (npcClass != null) {
|
||||
npcClass.config.forEach { t ->
|
||||
val value = parent.dto.variables[t.variableName] ?: t.defaultValue
|
||||
addEntry(ConfigVariable(t, value, this))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getScrollbarPosition() = x + width - 3
|
||||
|
||||
public override fun addEntry(entry: ConfigVariable) = super.addEntry(entry)
|
||||
public override fun removeEntry(entry: ConfigVariable) = super.removeEntry(entry)
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
correctSize()
|
||||
|
||||
super.renderWidget(context, mouseX, mouseY, partialTicks)
|
||||
|
||||
// Scroll Overlay
|
||||
// blitk(
|
||||
// matrixStack = context.pose(),
|
||||
// texture = scrollOverlayResource,
|
||||
// x = listX,
|
||||
// y = listY - 13,
|
||||
// height = 131,
|
||||
// width = WIDTH
|
||||
// )
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
updateScrollingState(mouseX, mouseY)
|
||||
if (scrolling) {
|
||||
focused = getEntryAtPosition(mouseX, mouseY)
|
||||
isDragging = true
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean {
|
||||
if (scrolling) {
|
||||
if (mouseY < this.listY) {
|
||||
scrollAmount = 0.0
|
||||
} else if (mouseY > bottom) {
|
||||
scrollAmount = maxScroll.toDouble()
|
||||
} else {
|
||||
scrollAmount += deltaY
|
||||
}
|
||||
}
|
||||
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)
|
||||
}
|
||||
|
||||
private fun updateScrollingState(mouseX: Double, mouseY: Double) {
|
||||
scrolling = mouseX >= this.scrollbarPosition.toDouble()
|
||||
&& mouseX < (this.scrollbarPosition + 3).toDouble()
|
||||
&& mouseY >= listY
|
||||
&& mouseY < bottom
|
||||
}
|
||||
|
||||
override fun renderListBackground(context: GuiGraphics) {}
|
||||
|
||||
private fun correctSize() {
|
||||
setRectangle(WIDTH, HEIGHT, listX, (listY - 4))
|
||||
// setX(listX)
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Double, mouseY: Double) = mouseX.toFloat() in (x.toFloat()..(x.toFloat() + WIDTH)) && mouseY.toFloat() in (y.toFloat()..(y.toFloat() + HEIGHT))
|
||||
|
||||
class ConfigVariable(val variable: NPCConfigVariable, val value: String, private val parent: ConfigVariableList) : Entry<ConfigVariable>() {
|
||||
val client: Minecraft = Minecraft.getInstance()
|
||||
var _focused = false
|
||||
var children = mutableListOf<GuiEventListener>()
|
||||
|
||||
var textValue = value
|
||||
var booleanValue = value.let { it.toDoubleOrNull() == 1.0 || it.toBooleanStrictOrNull() == true }
|
||||
|
||||
val editBox = EditBox(
|
||||
client.font,
|
||||
parent.listX,
|
||||
parent.listY + 4,
|
||||
if (variable.type == NPCVariableType.NUMBER) SLOT_WIDTH - 100 else SLOT_WIDTH,
|
||||
SLOT_HEIGHT - 8,
|
||||
variable.displayName,
|
||||
).also {
|
||||
it.tooltip = Tooltip.create(variable.description)
|
||||
it.height = SLOT_HEIGHT - 16
|
||||
it.setMaxLength(250)
|
||||
it.value = value
|
||||
it.setResponder {
|
||||
textValue = it
|
||||
parent.parent.dto.variables[variable.variableName] = it
|
||||
}
|
||||
if (variable.type == NPCVariableType.NUMBER) {
|
||||
it.setFilter { value -> value.toDoubleOrNull() != null || value.isBlank() || value == "." || value == "-" }
|
||||
}
|
||||
}
|
||||
val cycleButton = CycleButton.onOffBuilder(booleanValue).create(variable.displayName) { _, value ->
|
||||
booleanValue = value
|
||||
parent.parent.dto.variables[variable.variableName] = if (value) "1" else "0"
|
||||
}.also {
|
||||
it.height = SLOT_HEIGHT - 14
|
||||
it.width = SLOT_WIDTH - 8
|
||||
it.tooltip = Tooltip.create(variable.description)
|
||||
}
|
||||
|
||||
init {
|
||||
if (variable.type == NPCVariableType.BOOLEAN) {
|
||||
children.add(cycleButton)
|
||||
} else {
|
||||
children.add(editBox)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isFocused() = _focused
|
||||
override fun setFocused(focused: Boolean) {
|
||||
this._focused = focused
|
||||
}
|
||||
|
||||
override fun children() = children
|
||||
override fun narratables(): List<NarratableEntry> {
|
||||
return children.filterIsInstance<NarratableEntry>()
|
||||
}
|
||||
|
||||
override fun render(
|
||||
context: GuiGraphics,
|
||||
index: Int,
|
||||
rowTop: Int,
|
||||
rowLeft: Int,
|
||||
rowWidth: Int,
|
||||
rowHeight: Int,
|
||||
mouseX: Int,
|
||||
mouseY: Int,
|
||||
isHovered: Boolean,
|
||||
partialTicks: Float
|
||||
) {
|
||||
val x = rowLeft - 4
|
||||
val y = rowTop
|
||||
val matrixStack = context.pose()
|
||||
// blitk(
|
||||
// matrixStack = matrixStack,
|
||||
// texture = slotResource,
|
||||
// x = x,
|
||||
// y = y,
|
||||
// height = SLOT_HEIGHT,
|
||||
// width = rowWidth,
|
||||
// vOffset = if (isHovered) SLOT_HEIGHT else 0,
|
||||
// textureHeight = SLOT_HEIGHT * 2
|
||||
// )
|
||||
|
||||
if (variable.type == NPCVariableType.BOOLEAN) {
|
||||
cycleButton.x = x
|
||||
cycleButton.y = y + 6
|
||||
cycleButton.render(context, mouseX, mouseY, partialTicks)
|
||||
} else {
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = variable.displayName.visualOrderText,
|
||||
x = x,
|
||||
y = y + 4
|
||||
)
|
||||
editBox.x = x
|
||||
editBox.y = y + 14
|
||||
editBox.render(context, mouseX, mouseY, partialTicks)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// override fun mouseClicked(mouseX: Double, mouseY: Double, delta: Int): Boolean {
|
||||
// if (moveButton.isHovered(mouseX, mouseY) && canUnpasture()) {
|
||||
// moveButton.onPress()
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
}
|
||||
}
|
||||
+2
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.gui.pokedex.widgets
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.gui.ParentWidget
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
@@ -688,6 +689,7 @@ class PokemonInfoWidget(val pX: Int, val pY: Int, val updateForm: (PokedexForm)
|
||||
fun isWithinPortraitSpace(mouseX: Double, mouseY: Double): Boolean =
|
||||
mouseX.toInt() in pX + 15..(pX + 15 + PORTRAIT_POKE_BALL_WIDTH)
|
||||
&& mouseY.toInt() in pY + 25..(pY + 25 + PORTRAIT_POKE_BALL_HEIGHT)
|
||||
&& !children.any { it.isMouseOver(mouseX, mouseY) && it is ScaledButton }
|
||||
|
||||
private fun isSelectedPokemonOwned(): Boolean {
|
||||
return currentEntry?.let { CobblemonClient.clientPokedexData.getKnowledgeForSpecies(it.speciesId) } == PokedexEntryProgress.CAUGHT
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ class BedrockSoundKeyframe(
|
||||
if (entity != null) {
|
||||
entity.level().playLocalSound(entity, soundEvent, entity.soundSource, 1F, 1F)
|
||||
} else {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1F))
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1F, 1F))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -122,12 +122,11 @@ class PokemonRenderer(
|
||||
}
|
||||
if(entity.platform != PlatformType.NONE) {
|
||||
drawPlatform(
|
||||
poseMatrix,
|
||||
entity,
|
||||
(entity.delegate as PokemonClientDelegate).entityScaleModifier,
|
||||
partialTicks,
|
||||
buffer,
|
||||
packedLight,
|
||||
poseMatrix,
|
||||
entity,
|
||||
(entity.delegate as PokemonClientDelegate).entityScaleModifier,
|
||||
buffer,
|
||||
packedLight,
|
||||
)
|
||||
// keeps the pokemon's root on the raft
|
||||
poseMatrix.translate(0.0, 0.25 * (entity.delegate as PokemonClientDelegate).entityScaleModifier, 0.0)
|
||||
@@ -442,11 +441,10 @@ class PokemonRenderer(
|
||||
matrixStack: PoseStack,
|
||||
entity: PokemonEntity,
|
||||
scale: Float = 1F,
|
||||
partialTicks: Float,
|
||||
buff: MultiBufferSource,
|
||||
packedLight: Int,
|
||||
) {
|
||||
val (modelResource, textureResource) = PlatformType.GetModelWithTexture(entity.platform)
|
||||
val (modelResource, textureResource) = PlatformType.getModelWithTexture(entity.platform)
|
||||
val model = MiscModelRepository.modelOf(modelResource) ?: return
|
||||
matrixStack.pushPose()
|
||||
matrixStack.mulPose(Axis.ZP.rotationDegrees(180f))
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.data
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.CobblemonFlows
|
||||
import com.cobblemon.mod.common.CobblemonBrainConfigs
|
||||
import com.cobblemon.mod.common.CobblemonMechanics
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
@@ -91,6 +92,7 @@ object CobblemonDataProvider : DataProvider {
|
||||
this.register(DexEntryAdditions)
|
||||
this.register(Dexes)
|
||||
this.register(DexAdditions)
|
||||
this.register(CobblemonFlows)
|
||||
|
||||
CobblemonSpawnPools.load()
|
||||
this.register(PokeRods)
|
||||
|
||||
@@ -9,10 +9,8 @@
|
||||
package com.cobblemon.mod.common.entity
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import java.text.Normalizer
|
||||
import java.util.EnumSet
|
||||
|
||||
/**
|
||||
@@ -31,10 +29,9 @@ enum class PlatformType {
|
||||
|
||||
|
||||
companion object {
|
||||
val ALL_POSES = EnumSet.allOf(PlatformType::class.java)
|
||||
val WATER = EnumSet.of(WATER_XS, WATER_S, WATER_M, WATER_L, WATER_XL)
|
||||
|
||||
fun GetModelWithTexture(type: PlatformType) : Pair<ResourceLocation, ResourceLocation> {
|
||||
fun getModelWithTexture(type: PlatformType) : Pair<ResourceLocation, ResourceLocation> {
|
||||
return when (type) {
|
||||
WATER_XS -> Pair(cobblemonResource("water_platform_xs.geo"), cobblemonResource("textures/platforms/water_platform_xs.png"))
|
||||
WATER_S -> Pair(cobblemonResource("water_platform_s.geo"), cobblemonResource("textures/platforms/water_platform_s.png"))
|
||||
@@ -45,7 +42,7 @@ enum class PlatformType {
|
||||
}
|
||||
}
|
||||
|
||||
fun GetPlatformTypeForPokemon(form: FormData) : PlatformType {
|
||||
fun getPlatformTypeForPokemon(form: FormData) : PlatformType {
|
||||
val width = form.hitbox.width * form.baseScale
|
||||
|
||||
return if (width <= 0.511) {
|
||||
|
||||
@@ -16,7 +16,7 @@ import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
object AttackAngryAtTask {
|
||||
fun create(): OneShot<in LivingEntity> = BehaviorBuilder.create {
|
||||
fun create(): OneShot<in LivingEntity> = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.ANGRY_AT),
|
||||
it.registered(MemoryModuleType.ATTACK_TARGET)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.entity.ai
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
|
||||
class LookInDirectionTask(
|
||||
val yaw: Expression = "0".asExpression(),
|
||||
val pitch: Expression = "0".asExpression()
|
||||
) : Behavior<LivingEntity>(ImmutableMap.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT), 0, 0) {
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return !entity.brain.getMemory(MemoryModuleType.LOOK_TARGET).isPresent
|
||||
}
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
return owner is PathfinderMob && !owner.brain.getMemory(MemoryModuleType.LOOK_TARGET).isPresent
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
entity as PathfinderMob
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val yaw = (runtime.resolveFloat(this.yaw) + 90) * Math.PI / 180.0
|
||||
val pitch = runtime.resolveFloat(this.pitch) * Math.PI / 180.0 * -1
|
||||
|
||||
val xDisp = Math.cos(yaw)
|
||||
val zDisp = Math.sin(yaw)
|
||||
val yDisp = Math.sin(pitch)
|
||||
|
||||
entity.lookControl.setLookAt(entity.x + xDisp, entity.y + entity.eyeHeight + yDisp, entity.z + zDisp)
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -350,7 +350,7 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
entityData.set(CAUGHT_FISH, true)
|
||||
}
|
||||
} else if (this.waitCountdown > 0) {
|
||||
this.waitCountdown -= i
|
||||
this.waitCountdown -= i + lureLevel
|
||||
var f = 0.15f
|
||||
if (this.waitCountdown < 20) {
|
||||
f += (20 - this.waitCountdown).toFloat() * 0.05f
|
||||
@@ -392,10 +392,9 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
|
||||
// set the time it takes to wait for a hooked item or pokemon
|
||||
this.waitCountdown = Mth.nextInt(random, 100, 600)
|
||||
this.waitCountdown -= this.lureLevel * 20 * 5
|
||||
|
||||
if (this.waitCountdown < 0)
|
||||
this.waitCountdown = 0
|
||||
if (this.waitCountdown <= 0)
|
||||
this.waitCountdown = 1
|
||||
else {
|
||||
// check for the bait on the hook and see if the waitCountdown is reduced
|
||||
if (checkReduceBiteTime(bobberBait))
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.entity.npc
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.AIBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
@@ -49,11 +48,6 @@ class NPCBattleActor(
|
||||
skill
|
||||
)
|
||||
|
||||
override fun setupStruct() {
|
||||
super.setupStruct()
|
||||
struct.addFunction("skill") { DoubleValue(skill) }
|
||||
}
|
||||
|
||||
override fun sendUpdate(packet: NetworkPacket<*>) {
|
||||
super.sendUpdate(packet)
|
||||
if (packet is BattleEndPacket) {
|
||||
|
||||
@@ -126,17 +126,20 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
|
||||
var allowProjectileHits: Boolean? = null
|
||||
|
||||
fun getPartyForChallenge(player: ServerPlayer): NPCPartyStore? {
|
||||
fun getPartyForChallenge(players: List<ServerPlayer>): NPCPartyStore? {
|
||||
val party = this.party
|
||||
return if (party != null) {
|
||||
party
|
||||
} else if (npc.party?.isStatic == false) {
|
||||
npc.party?.provide(this, level)
|
||||
npc.party?.provide(this, level, players)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/** Oi, dev, you no touch this one. This one is for [com.cobblemon.mod.common.api.npc.variation.NPCVariationProvider]s. */
|
||||
val variationAspects = mutableSetOf<String>()
|
||||
/** You can add to this one if you want, that's ok. */
|
||||
val appliedAspects = mutableSetOf<String>()
|
||||
override val delegate = if (world.isClientSide) {
|
||||
com.cobblemon.mod.common.client.entity.NPCClientDelegate()
|
||||
@@ -283,7 +286,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
override fun getBrain() = super.getBrain() as Brain<NPCEntity>
|
||||
|
||||
fun updateAspects() {
|
||||
entityData.set(ASPECTS, appliedAspects)
|
||||
entityData.set(ASPECTS, appliedAspects + variationAspects)
|
||||
}
|
||||
|
||||
fun isInBattle() = battleIds.isNotEmpty()
|
||||
@@ -317,6 +320,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
nbt.put(DataKeys.NPC_LEVEL, IntTag.valueOf(level))
|
||||
nbt.putString(DataKeys.NPC_CLASS, npc.id.toString())
|
||||
nbt.put(DataKeys.NPC_ASPECTS, ListTag().also { list -> appliedAspects.forEach { list.add(StringTag.valueOf(it)) } })
|
||||
nbt.put(DataKeys.NPC_VARIATION_ASPECTS, ListTag().also { list -> variationAspects.forEach { list.add(StringTag.valueOf(it)) } })
|
||||
interaction?.let {
|
||||
val interactionNBT = CompoundTag()
|
||||
interactionNBT.putString(DataKeys.NPC_INTERACT_TYPE, it.type)
|
||||
@@ -374,6 +378,7 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
data = MoLangFunctions.readMoValueFromNBT(nbt.getCompound(DataKeys.NPC_DATA)) as VariableStruct
|
||||
config = if (nbt.contains(DataKeys.NPC_CONFIG)) MoLangFunctions.readMoValueFromNBT(nbt.getCompound(DataKeys.NPC_CONFIG)) as VariableStruct else VariableStruct()
|
||||
appliedAspects.addAll(nbt.getList(DataKeys.NPC_ASPECTS, Tag.TAG_STRING.toInt()).map { it.asString })
|
||||
variationAspects.addAll(nbt.getList(DataKeys.NPC_VARIATION_ASPECTS, Tag.TAG_STRING.toInt()).map { it.asString })
|
||||
nbt.getCompound(DataKeys.NPC_INTERACTION).takeIf { !it.isEmpty }?.let { nbt ->
|
||||
val type = nbt.getString("type")
|
||||
val configType = NPCInteractConfiguration.types[type] ?: return@let
|
||||
@@ -449,10 +454,10 @@ class NPCEntity(world: Level) : AgeableMob(CobblemonEntities.NPC, world), Npc, P
|
||||
}
|
||||
|
||||
fun initialize(level: Int) {
|
||||
appliedAspects.clear()
|
||||
variationAspects.clear()
|
||||
entityData.set(LEVEL, level)
|
||||
npc.config.forEach { it.applyDefault(this) }
|
||||
npc.variations.values.forEach { this.appliedAspects.addAll(it.provideAspects(this)) }
|
||||
npc.variations.values.forEach { this.variationAspects.addAll(it.provideAspects(this)) }
|
||||
if (party == null || npc.party != null) {
|
||||
party = npc.party?.takeIf { it.isStatic }?.provide(this, level)
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityP
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.util.asArrayValue
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.client.Minecraft
|
||||
@@ -118,6 +119,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
override val struct = QueryStruct(hashMapOf())
|
||||
.addFunction("capture_state") { StringValue(captureState.name) }
|
||||
.addFunction("ball_type") { StringValue(pokeBall.name.toString()) }
|
||||
.addFunction("aspects") { aspects.asArrayValue { StringValue(it) } }
|
||||
|
||||
override fun defineSynchedData(builder: SynchedEntityData.Builder) {
|
||||
pokeBall = PokeBalls.POKE_BALL
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.entity.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.*
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonEntities
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.drop.DropTable
|
||||
import com.cobblemon.mod.common.api.entity.Despawner
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSender
|
||||
@@ -24,6 +26,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addEntityFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonEntityFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.net.serializers.PlatformTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
||||
@@ -73,14 +76,28 @@ import com.cobblemon.mod.common.pokemon.activestate.InactivePokemonState
|
||||
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
|
||||
import com.cobblemon.mod.common.pokemon.ai.FormPokemonBehaviour
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.feature.StashHandler
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.getBitForByte
|
||||
import com.cobblemon.mod.common.util.giveOrDropItemStack
|
||||
import com.cobblemon.mod.common.util.isPokemonEntity
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.playSoundServer
|
||||
import com.cobblemon.mod.common.util.setBitForByte
|
||||
import com.cobblemon.mod.common.util.toNbtList
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import com.mojang.serialization.Codec
|
||||
import java.util.EnumSet
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.nbt.NbtUtils
|
||||
import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.network.chat.Component
|
||||
@@ -89,14 +106,10 @@ import net.minecraft.network.protocol.Packet
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener
|
||||
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
|
||||
import net.minecraft.network.protocol.game.DebugPackets
|
||||
import net.minecraft.network.syncher.EntityDataAccessor
|
||||
import net.minecraft.network.syncher.EntityDataSerializers
|
||||
import net.minecraft.network.syncher.SynchedEntityData
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.network.protocol.game.DebugPackets
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerEntity
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -109,7 +122,15 @@ import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.damagesource.DamageTypes
|
||||
import net.minecraft.world.effect.MobEffects
|
||||
import net.minecraft.world.entity.*
|
||||
import net.minecraft.world.entity.AgeableMob
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.EntityDimensions
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.entity.EquipmentSlot
|
||||
import net.minecraft.world.entity.ExperienceOrb
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Pose
|
||||
import net.minecraft.world.entity.Shearable
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes
|
||||
import net.minecraft.world.entity.ai.control.MoveControl
|
||||
@@ -267,11 +288,12 @@ open class PokemonEntity(
|
||||
get() = entityData.get(PLATFORM_TYPE)
|
||||
set(value) { entityData.set(PLATFORM_TYPE, value) }
|
||||
|
||||
override val struct: QueryStruct = QueryStruct(hashMapOf())
|
||||
.addStandardFunctions()
|
||||
.addEntityFunctions(this)
|
||||
.addPokemonFunctions(pokemon)
|
||||
.addPokemonEntityFunctions(this)
|
||||
override val struct: ObjectValue<PokemonEntity> = ObjectValue(this).also {
|
||||
it.addStandardFunctions()
|
||||
.addEntityFunctions(this)
|
||||
.addPokemonFunctions(pokemon)
|
||||
.addPokemonEntityFunctions(this)
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
@@ -367,9 +389,21 @@ open class PokemonEntity(
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (!this.isBattling && this.beamMode == 0 && this.isBattleClone()) {
|
||||
discard()
|
||||
return
|
||||
if (isBattling) {
|
||||
// Deploy a platform if a non-wild Pokemon is touching water but not underwater.
|
||||
// This can't be done in the BattleMovementGoal as the sleep goal will override it.
|
||||
if (ticksLived > 5 && platform == PlatformType.NONE
|
||||
&& this.ownerUUID != null
|
||||
&& isInWater && !isUnderWater
|
||||
&& !exposedForm.behaviour.moving.swim.canBreatheUnderwater && !exposedForm.behaviour.moving.swim.canWalkOnWater) {
|
||||
platform = PlatformType.getPlatformTypeForPokemon((exposedForm))
|
||||
}
|
||||
} else {
|
||||
// Battle clone destruction
|
||||
if (this.beamMode == 0 && this.isBattleClone()) {
|
||||
discard()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// We will be handling idle logic ourselves thank you
|
||||
@@ -1138,13 +1172,12 @@ open class PokemonEntity(
|
||||
var blockPos = BlockPos(pos.x.toInt(), pos.y.toInt(), pos.z.toInt())
|
||||
var blockLookCount = 5
|
||||
var foundSurface = false
|
||||
val species = this.exposedSpecies
|
||||
val form = this.exposedForm
|
||||
var result = pos
|
||||
if (this.level().isWaterAt(blockPos)) {
|
||||
// look upward for a water surface
|
||||
var testPos = blockPos
|
||||
if (!species.behaviour.moving.swim.canBreatheUnderwater) {
|
||||
if (!form.behaviour.moving.swim.canBreatheUnderwater || form.behaviour.moving.fly.canFly) {
|
||||
// move sendout pos to surface if it's near
|
||||
for (i in 0..blockLookCount) {
|
||||
// Try to find a surface...
|
||||
@@ -1185,15 +1218,15 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
if (foundSurface) {
|
||||
val canFly = species.behaviour.moving.fly.canFly
|
||||
val canFly = form.behaviour.moving.fly.canFly
|
||||
if (canFly) {
|
||||
val hasHeadRoom = !collidesWithBlock(Vec3(blockPos.x.toDouble(), (result.y + 1), (blockPos.z).toDouble()))
|
||||
if (hasHeadRoom) {
|
||||
result = Vec3(result.x, result.y + 1.0, result.z)
|
||||
}
|
||||
} else if (species.behaviour.moving.swim.canBreatheUnderwater && !species.behaviour.moving.swim.canWalkOnWater) {
|
||||
} else if (form.behaviour.moving.swim.canBreatheUnderwater && !form.behaviour.moving.swim.canWalkOnWater) {
|
||||
// Use half hitbox height for swimmers
|
||||
val halfHeight = species.hitbox.height * species.baseScale / 2.0
|
||||
val halfHeight = form.hitbox.height * form.baseScale / 2.0
|
||||
for (i in 1..halfHeight.toInt()) {
|
||||
blockPos = blockPos.below()
|
||||
if (!this.level().isWaterAt(blockPos) || !this.level().getBlockState(blockPos).getCollisionShape(this.level(), blockPos).isEmpty) {
|
||||
@@ -1202,7 +1235,7 @@ open class PokemonEntity(
|
||||
}
|
||||
result = Vec3(result.x, result.y + halfHeight - halfHeight.toInt(), result.z)
|
||||
} else {
|
||||
platform = if (species.behaviour.moving.swim.canWalkOnWater || collidesWithBlock(Vec3(result.x, result.y, result.z))) PlatformType.NONE else PlatformType.GetPlatformTypeForPokemon(form)
|
||||
platform = if (form.behaviour.moving.swim.canWalkOnWater || collidesWithBlock(Vec3(result.x, result.y, result.z))) PlatformType.NONE else PlatformType.getPlatformTypeForPokemon(form)
|
||||
}
|
||||
}
|
||||
this.platform = platform
|
||||
|
||||
+3
-3
@@ -201,7 +201,7 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
|
||||
// Borrowing hard from Minecraft's Boat logic
|
||||
if (this.pokemonEntity.isBattling && mob.isInWater) {
|
||||
var e = 0.0F
|
||||
val exposedSpecies = this.pokemonEntity.exposedSpecies
|
||||
val exposedForm = this.pokemonEntity.exposedForm
|
||||
if (isUnderwater()) {
|
||||
if (this.pokemonEntity.platform != PlatformType.NONE) {
|
||||
// Float up if on a platform
|
||||
@@ -211,7 +211,7 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
|
||||
if (this.pokemonEntity.platform != PlatformType.NONE ) {
|
||||
// Hold Steady
|
||||
e = ((this.waterLevel - this.pokemonEntity.y) / this.pokemonEntity.bbHeight).toFloat()
|
||||
} else if (exposedSpecies.behaviour.moving.swim.canBreatheUnderwater) {
|
||||
} else if (exposedForm.behaviour.moving.swim.canBreatheUnderwater) {
|
||||
// allow swimmers to sink a bit into the water
|
||||
e = -1.5F
|
||||
}
|
||||
@@ -230,7 +230,7 @@ class PokemonMoveControl(val pokemonEntity: PokemonEntity) : MoveControl(pokemon
|
||||
*/
|
||||
private fun getStableBattleFloatHeight(): Double {
|
||||
val aABB: AABB = this.pokemonEntity.boundingBox
|
||||
return if (this.pokemonEntity.exposedSpecies.behaviour.moving.swim.canBreatheUnderwater) ((aABB.maxY - aABB.minY) / 2.0) else 0.05
|
||||
return if (this.pokemonEntity.exposedForm.behaviour.moving.swim.canBreatheUnderwater) ((aABB.maxY - aABB.minY) / 2.0) else 0.05
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+6
-1
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.entity.pokemon.ai.goals
|
||||
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.entity.PlatformType
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -43,7 +44,7 @@ class PokemonInBattleMovementGoal(val entity: PokemonEntity, val range: Int) : G
|
||||
entity.lookControl.setLookAt(closestPokemonEntity.x, closestPokemonEntity.eyeY, closestPokemonEntity.z)
|
||||
}
|
||||
|
||||
if (entity.exposedSpecies.behaviour.moving.fly.canFly) {
|
||||
if (entity.exposedForm.behaviour.moving.fly.canFly) {
|
||||
// Flyer logic
|
||||
if (!hasMovedToPos) {
|
||||
entity.navigation.moveTo(battlePos!!.x, battlePos!!.y, battlePos!!.z, 1.0)
|
||||
@@ -54,5 +55,9 @@ class PokemonInBattleMovementGoal(val entity: PokemonEntity, val range: Int) : G
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
|
||||
}
|
||||
}
|
||||
if (entity.platform != PlatformType.NONE && entity.onGround()) {
|
||||
// If the pokemon is on a non-fluid surface, remove the platform.
|
||||
entity.platform = PlatformType.NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -47,7 +47,7 @@ class IllusionEffect(
|
||||
override fun revert(entity: PokemonEntity, future: CompletableFuture<PokemonEntity>) {
|
||||
entity.effects.mockEffect = null
|
||||
|
||||
if (!entity.exposedSpecies.behaviour.moving.fly.canFly && entity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) {
|
||||
if (!entity.exposedForm.behaviour.moving.fly.canFly && entity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) {
|
||||
// Transitioning from a flying form to a non-flying form.
|
||||
// If we were flying, need to turn the behavior flag off or the pokemon will continue to float in the air.
|
||||
entity.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.events
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonFlows
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
|
||||
/**
|
||||
* Handles the registration of the default Cobblemon event hooks into flows.
|
||||
*/
|
||||
object FlowHandler {
|
||||
fun setup() {
|
||||
CobblemonEvents.POKEMON_CAPTURED.subscribe { CobblemonFlows.run(cobblemonResource("pokemon_captured"), it.context) }
|
||||
CobblemonEvents.BATTLE_VICTORY.subscribe { CobblemonFlows.run(cobblemonResource("battle_victory"), it.context) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,44 +228,6 @@ object CobblemonItemGroups {
|
||||
entries.accept(CobblemonItems.DARK_GEM)
|
||||
entries.accept(CobblemonItems.STEEL_GEM)
|
||||
entries.accept(CobblemonItems.FAIRY_GEM)
|
||||
|
||||
entries.accept(CobblemonItems.GEM_NORMAL_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_FIRE_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_WATER_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_GRASS_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_ELECTRIC_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_ICE_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_FIGHTING_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_POISON_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_GROUND_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_FLYING_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_PSYCHIC_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_BUG_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_ROCK_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_GHOST_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_DRAGON_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_DARK_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_STEEL_BLOCK)
|
||||
entries.accept(CobblemonItems.GEM_FAIRY_BLOCK)
|
||||
|
||||
entries.accept(CobblemonItems.GEM_NORMAL_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_FIRE_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_WATER_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_GRASS_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_ELECTRIC_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_ICE_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_FIGHTING_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_POISON_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_GROUND_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_FLYING_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_PSYCHIC_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_BUG_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_ROCK_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_GHOST_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_DRAGON_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_DARK_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_STEEL_BUDDING)
|
||||
entries.accept(CobblemonItems.GEM_FAIRY_BUDDING)
|
||||
}
|
||||
|
||||
private fun blockEntries(displayContext: ItemDisplayParameters, entries: Output) {
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.data
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonFlows
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* A packet that synchronizes the flow registry with the client.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 24th, 2024
|
||||
*/
|
||||
class FlowRegistrySyncPacket(entries: Collection<Map.Entry<ResourceLocation, List<ExpressionLike>>>) : DataRegistrySyncPacket<Map.Entry<ResourceLocation, List<ExpressionLike>>, FlowRegistrySyncPacket>(entries){
|
||||
companion object {
|
||||
val ID = cobblemonResource("flow_registry_sync")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): FlowRegistrySyncPacket = FlowRegistrySyncPacket(emptyList()).apply { decodeBuffer(buffer) }
|
||||
}
|
||||
|
||||
override val id = ID
|
||||
|
||||
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: Map.Entry<ResourceLocation, List<ExpressionLike>>) {
|
||||
buffer.writeIdentifier(entry.key)
|
||||
buffer.writeCollection(entry.value) { _, expression -> buffer.writeString(expression.toString()) }
|
||||
}
|
||||
|
||||
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): Map.Entry<ResourceLocation, List<ExpressionLike>> {
|
||||
val key = buffer.readIdentifier()
|
||||
val value = buffer.readList { buffer.readString().asExpressionLike() }
|
||||
return object : Map.Entry<ResourceLocation, List<ExpressionLike>> {
|
||||
override val key = key
|
||||
override val value = value
|
||||
}
|
||||
}
|
||||
|
||||
override fun synchronizeDecoded(entries: Collection<Map.Entry<ResourceLocation, List<ExpressionLike>>>) {
|
||||
entries.map { (identifier, flows) ->
|
||||
val existing = CobblemonFlows.clientFlows.getOrPut(identifier) { mutableListOf() }
|
||||
existing += flows
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-1
@@ -16,7 +16,13 @@ import com.cobblemon.mod.common.api.npc.configuration.NPCBattleConfiguration
|
||||
import com.cobblemon.mod.common.api.npc.configuration.NPCInteractConfiguration
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.readText
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import com.cobblemon.mod.common.util.writeText
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
@@ -29,6 +35,7 @@ class NPCConfigurationDTO : Encodable, Decodable {
|
||||
var interactionInherited: Boolean = false
|
||||
var interaction: NPCInteractConfiguration? = null
|
||||
var aspects: MutableSet<String> = mutableSetOf()
|
||||
var variables: MutableMap<String, String> = mutableMapOf()
|
||||
|
||||
constructor()
|
||||
|
||||
@@ -39,6 +46,7 @@ class NPCConfigurationDTO : Encodable, Decodable {
|
||||
interactionInherited = npcEntity.interaction == null
|
||||
interaction = npcEntity.interaction ?: npcEntity.npc.interaction
|
||||
aspects = npcEntity.appliedAspects
|
||||
variables = npcEntity.config.map.map { it.key to it.value.asString() }.toMap().toMutableMap()
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -51,6 +59,11 @@ class NPCConfigurationDTO : Encodable, Decodable {
|
||||
value.encode(buffer)
|
||||
}
|
||||
buffer.writeCollection(aspects, ByteBuf::writeString)
|
||||
buffer.writeMap(
|
||||
variables,
|
||||
{ _, it -> buffer.writeString(it) },
|
||||
{ _, it -> buffer.writeString(it) },
|
||||
)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -64,6 +77,10 @@ class NPCConfigurationDTO : Encodable, Decodable {
|
||||
configType.clazz.getConstructor().newInstance().also { it.decode(buffer) }
|
||||
}
|
||||
aspects = buffer.readList { buffer.readString() }.toMutableSet()
|
||||
variables = buffer.readMap(
|
||||
{ buffer.readString() },
|
||||
{ buffer.readString() },
|
||||
).toMutableMap()
|
||||
}
|
||||
|
||||
fun apply(entity: NPCEntity) {
|
||||
@@ -78,5 +95,9 @@ class NPCConfigurationDTO : Encodable, Decodable {
|
||||
}
|
||||
entity.appliedAspects.clear()
|
||||
entity.appliedAspects.addAll(aspects)
|
||||
variables.forEach { (key, value) ->
|
||||
val variable = entity.npc.config.find { it.variableName == key } ?: return@forEach
|
||||
entity.config.setDirectly(key, variable.type.toMoValue(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokeball
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.CaptureEffect
|
||||
import com.cobblemon.mod.common.api.pokeball.catching.CatchRateModifier
|
||||
@@ -39,6 +42,12 @@ open class PokeBall(
|
||||
val throwPower: Float,
|
||||
val ancient: Boolean
|
||||
) {
|
||||
val struct = QueryStruct(hashMapOf())
|
||||
.addFunction("name") { StringValue(name.toString()) }
|
||||
.addFunction("water_drag_value") { DoubleValue(waterDragValue) }
|
||||
.addFunction("throw_power") { DoubleValue(throwPower) }
|
||||
.addFunction("is_ancient") { DoubleValue(ancient) }
|
||||
// .addFunction("item") { } // requires a registry which is hard
|
||||
|
||||
// This gets attached during item registry
|
||||
internal lateinit var item: PokeBallItem
|
||||
|
||||
@@ -612,7 +612,7 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
if (owner is LivingEntity) {
|
||||
owner.swing(InteractionHand.MAIN_HAND, true)
|
||||
val spawnDirection: Vec3
|
||||
val spawnYaw: Double
|
||||
var spawnYaw: Double
|
||||
if (battleId != null) {
|
||||
// Look for an opposing opponent to face
|
||||
val battle = Cobblemon.battleRegistry.getBattle(battleId)
|
||||
@@ -640,6 +640,14 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
spawnDirection = position.subtract(owner.position())
|
||||
spawnYaw = atan2(spawnDirection.z, spawnDirection.x) * 180.0 / PI + 102.5
|
||||
}
|
||||
|
||||
// In some edge cases, I suspect we are producing NaN's here. This actually leads into a really big problem.
|
||||
// Why? Because on tick, LivingEntity tries to bring rotations back within one loop around 0-360 using while loops.
|
||||
// NaN resists arithmetic, so the while loops run forever and the server thread will hang trying to normalize
|
||||
// this angle. Better to catch it here and correct it. Y'know. If this is actually the problem. I believe!
|
||||
if (!spawnYaw.isFinite()) {
|
||||
spawnYaw = 0.0
|
||||
}
|
||||
it.entityData.set(PokemonEntity.SPAWN_DIRECTION, spawnYaw.toFloat())
|
||||
}
|
||||
if (owner != null) {
|
||||
|
||||
@@ -94,8 +94,7 @@ abstract class PokemonStats : Iterable<Map.Entry<Stat, Int>> {
|
||||
|
||||
Stats.PERMANENT.forEach { stat ->
|
||||
val identifier = this.cleanStatIdentifier(stat.identifier)
|
||||
this[stat] = json.get(identifier)?.asInt?.coerceIn(this.acceptableRange)
|
||||
?: this.defaultValue
|
||||
json.get(identifier)?.asInt?.coerceIn(this.acceptableRange)?.let { this.stats[stat] = it }
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
@@ -161,6 +164,21 @@ class Species : ClientDataSynchronizer<Species>, ShowdownIdentifiable {
|
||||
var lightingData: LightingData? = null
|
||||
private set
|
||||
|
||||
@Transient
|
||||
val struct = QueryStruct(hashMapOf())
|
||||
.addFunction("identifier") { StringValue(this.resourceIdentifier.toString()) }
|
||||
.addFunction("primary_type") { StringValue(this.primaryType.name) }
|
||||
.addFunction("secondary_type") { StringValue(this.secondaryType?.name ?: "null") }
|
||||
.addFunction("experience_group") { StringValue(this.experienceGroup.name) }
|
||||
.addFunction("height") { DoubleValue(this.height) }
|
||||
.addFunction("weight") { DoubleValue(this.weight) }
|
||||
.addFunction("base_scale") { DoubleValue(this.baseScale) }
|
||||
.addFunction("hitbox_width") { DoubleValue(this.hitbox.width) }
|
||||
.addFunction("hitbox_height") { DoubleValue(this.hitbox.height) }
|
||||
.addFunction("hitbox_fixed") { DoubleValue(this.hitbox.fixed) }
|
||||
.addFunction("catch_rate") { DoubleValue(this.catchRate) }
|
||||
|
||||
|
||||
fun initialize() {
|
||||
Cobblemon.statProvider.provide(this)
|
||||
this.forms.forEach { it.initialize(this) }
|
||||
|
||||
+13
-5
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.properties
|
||||
|
||||
import com.cobblemon.mod.common.api.abilities.CommonAbilityType
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
@@ -23,15 +24,20 @@ import com.cobblemon.mod.common.pokemon.abilities.HiddenAbilityType
|
||||
object HiddenAbilityPropertyType : CustomPokemonPropertyType<HiddenAbilityProperty> {
|
||||
override val keys = setOf("hiddenability", "ha")
|
||||
override val needsKey = true
|
||||
override fun fromString(value: String?) = HiddenAbilityProperty()
|
||||
override fun examples() = emptySet<String>()
|
||||
override fun fromString(value: String?) =
|
||||
when {
|
||||
value == null || value.lowercase() in listOf("true", "yes") -> HiddenAbilityProperty(true)
|
||||
value.lowercase() in listOf("false", "no") -> HiddenAbilityProperty(false)
|
||||
else -> null
|
||||
}
|
||||
override fun examples() = setOf("yes", "no")
|
||||
}
|
||||
|
||||
class HiddenAbilityProperty : CustomPokemonProperty {
|
||||
class HiddenAbilityProperty (var value: Boolean) : CustomPokemonProperty {
|
||||
override fun asString() = "hiddenability"
|
||||
override fun apply(pokemon: Pokemon) {
|
||||
val possible = pokemon.form.abilities.mapping.flatMap { it.value }
|
||||
.filter { it.type == HiddenAbilityType }
|
||||
.filter { it.type == getAbilityType() }
|
||||
val picked = possible.randomOrNull() ?: return
|
||||
pokemon.updateAbility(picked.template.create(false))
|
||||
}
|
||||
@@ -39,5 +45,7 @@ class HiddenAbilityProperty : CustomPokemonProperty {
|
||||
override fun matches(pokemon: Pokemon) = pokemon.form.abilities.mapping
|
||||
.flatMap { it.value }
|
||||
.find { it.template == pokemon.ability.template }
|
||||
?.type == HiddenAbilityType
|
||||
?.type == getAbilityType()
|
||||
|
||||
private fun getAbilityType() = if (this.value) HiddenAbilityType else CommonAbilityType
|
||||
}
|
||||
+1
@@ -146,6 +146,7 @@ internal object PropertiesCompletionProvider : DataRegistry {
|
||||
this.inject(setOf("tradeable"), setOf("yes", "no"))
|
||||
this.inject(setOf("originaltrainer", "ot"), setOf(""))
|
||||
this.inject(setOf("originaltrainertype", "ottype"), setOf("None", "Player", "NPC"))
|
||||
this.inject(setOf("nickname", "nick"), setOf(""))
|
||||
|
||||
Stats.PERMANENT.forEach{ stat ->
|
||||
val statName = stat.toString().lowercase()
|
||||
|
||||
@@ -202,6 +202,7 @@ object DataKeys {
|
||||
const val NPC_PARTY = "Party"
|
||||
const val NPC_PARTY_TYPE = "PartyType"
|
||||
const val NPC_ASPECTS = "AppliedAspects"
|
||||
const val NPC_VARIATION_ASPECTS = "VariationAspects"
|
||||
const val NPC_DATA = "Data"
|
||||
const val NPC_CONFIG = "Config"
|
||||
const val NPC_INTERACTION = "Interaction"
|
||||
|
||||
@@ -37,6 +37,7 @@ fun String.asTranslated() = Component.translatable(this)
|
||||
fun String.asResource() = ResourceLocation.parse(this)
|
||||
fun String.asTranslated(vararg data: Any) = Component.translatable(this, *data)
|
||||
fun String.isInt() = this.toIntOrNull() != null
|
||||
fun String.isDouble() = this.toDoubleOrNull() != null
|
||||
fun String.isHigherVersion(other: String): Boolean {
|
||||
val thisSplits = split(".")
|
||||
val thatSplits = other.split(".")
|
||||
|
||||
@@ -41,7 +41,7 @@ fun MoLangRuntime.resolve(expression: Expression, context: Map<String, MoValue>
|
||||
}
|
||||
// expression.evaluate(MoScope(), environment)
|
||||
} catch (e: Exception) {
|
||||
throw IllegalArgumentException("Unable to parse expression: ${expression.getString()}", e)
|
||||
throw IllegalArgumentException("Unable to evaluate expression: ${expression.getString()}", e)
|
||||
}
|
||||
fun MoLangRuntime.resolveDouble(expression: Expression, context: Map<String, MoValue> = contextOrEmpty): Double = resolve(expression, context).asDouble()
|
||||
fun MoLangRuntime.resolveFloat(expression: Expression, context: Map<String, MoValue> = contextOrEmpty): Float = resolve(expression, context).asDouble().toFloat()
|
||||
@@ -210,8 +210,16 @@ fun MoLangEnvironment.cloneFrom(other: MoLangEnvironment): MoLangEnvironment {
|
||||
return this
|
||||
}
|
||||
|
||||
fun BlockPos.toArrayStruct() = ArrayStruct().apply {
|
||||
map["0"] = DoubleValue(x)
|
||||
map["1"] = DoubleValue(y)
|
||||
map["2"] = DoubleValue(z)
|
||||
fun BlockPos.toArrayStruct() = listOf(x, y, z).asArrayValue(::DoubleValue)
|
||||
|
||||
fun <T> Collection<T>.asArrayValue(mapper: (T) -> MoValue): ArrayStruct {
|
||||
val array = ArrayStruct()
|
||||
forEachIndexed { index, value -> array.setDirectly("$index", mapper(value)) }
|
||||
return array
|
||||
}
|
||||
|
||||
fun Iterable<MoValue>.asArrayValue(): ArrayStruct {
|
||||
val array = ArrayStruct()
|
||||
forEachIndexed { index, value -> array.setDirectly("$index", value) }
|
||||
return array
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.ChunkPos
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.phys.AABB
|
||||
@@ -153,6 +154,8 @@ val Level.enchantmentRegistry: Registry<Enchantment>
|
||||
get() = registryAccess().registryOrThrow(Registries.ENCHANTMENT)
|
||||
val Level.activityRegistry: Registry<Activity>
|
||||
get() = registryAccess().registryOrThrow(Registries.ACTIVITY)
|
||||
val Level.blockRegistry: Registry<Block>
|
||||
get() = registryAccess().registryOrThrow(Registries.BLOCK)
|
||||
|
||||
fun Vec3.traceDownwards(
|
||||
world: Level,
|
||||
|
||||
+7
-2
@@ -13,21 +13,26 @@ import com.cobblemon.mod.common.api.dialogue.ExpressionLikeDialogueText
|
||||
import com.cobblemon.mod.common.api.dialogue.WrappedDialogueText
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonParseException
|
||||
import com.mojang.serialization.JsonOps
|
||||
import java.lang.reflect.Type
|
||||
import net.minecraft.network.chat.ComponentSerialization
|
||||
|
||||
object DialogueTextAdapter : JsonDeserializer<DialogueText> {
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): DialogueText {
|
||||
return if (json.isJsonPrimitive) {
|
||||
WrappedDialogueText(json.asString.text())
|
||||
WrappedDialogueText(json.asString.asTranslated())
|
||||
} else if (json.isJsonArray) {
|
||||
ExpressionLikeDialogueText(json.asJsonArray.map { it.asString }.asExpressionLike())
|
||||
} else {
|
||||
val obj = json.asJsonObject
|
||||
val typeId = obj.get("type").asString
|
||||
val typeId = obj.get("type")?.asString ?: run {
|
||||
return WrappedDialogueText(ComponentSerialization.CODEC.decode(JsonOps.INSTANCE, json).result().get().first.copy())
|
||||
}
|
||||
val clazz = DialogueText.types[typeId] ?: throw JsonParseException("Unknown dialogue text type $typeId")
|
||||
context.deserialize(json, clazz)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.npc.NPCPartyProvider
|
||||
import com.cobblemon.mod.common.api.npc.NPCPreset
|
||||
import com.cobblemon.mod.common.api.npc.NPCPresets
|
||||
import com.cobblemon.mod.common.api.npc.configuration.NPCBattleConfiguration
|
||||
import com.cobblemon.mod.common.api.npc.configuration.NPCConfigVariable
|
||||
import com.cobblemon.mod.common.api.npc.configuration.NPCInteractConfiguration
|
||||
import com.cobblemon.mod.common.api.npc.variation.NPCVariationProvider
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
@@ -60,6 +61,10 @@ object NPCClassAdapter : JsonDeserializer<NPCClass> {
|
||||
obj.get("battleConfiguration")?.let { npcClass.battleConfiguration = ctx.deserialize(it, NPCBattleConfiguration::class.java) }
|
||||
obj.get("interaction")?.let { npcClass.interaction = ctx.deserialize(it, NPCInteractConfiguration::class.java) }
|
||||
obj.get("canDespawn")?.let { npcClass.canDespawn = it.asBoolean }
|
||||
obj.get("config")?.let {
|
||||
val obj = it.asJsonArray
|
||||
obj.forEach { npcClass.config.add(ctx.deserialize(it, NPCConfigVariable::class.java)) }
|
||||
}
|
||||
obj.get("variations")?.let {
|
||||
val obj = it.asJsonObject
|
||||
obj.entrySet().forEach { (key, value) ->
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.util.adapters
|
||||
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.mojang.serialization.JsonOps
|
||||
import java.lang.reflect.Type
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.ComponentSerialization
|
||||
|
||||
/**
|
||||
* Kinda like [TextAdapter] but it treats them as translatables.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 26th, 2024
|
||||
*/
|
||||
object TranslatedTextAdapter : JsonDeserializer<Component> {
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, ctx: JsonDeserializationContext) : Component {
|
||||
return if (json.isJsonObject) {
|
||||
ComponentSerialization.CODEC.decode(JsonOps.INSTANCE, json).result().get().first
|
||||
} else {
|
||||
json.asString.asTranslated()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ package com.cobblemon.mod.common.util.codec
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import com.mojang.serialization.MapCodec
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import java.util.Optional
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
//Codec.optionalFieldOf uses Java Optionals, which cant be passed into constructors using Kotlin optionals.
|
||||
fun <T> Codec<T>.kotlinOptionalFieldOf(name: String): MapCodec<T?> {
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
"events": {
|
||||
"poisonHit": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:status.poison.actor"
|
||||
"event_name": "cobblemon:status.nonvolatile.poison.actor"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
"events": {
|
||||
"toxicHit": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:status.badlypoison.actor"
|
||||
"event_name": "cobblemon:status.nonvolatile.toxpoison.actor"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+10
@@ -8,6 +8,13 @@
|
||||
"texture": "textures/particles/bite"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.bite.target"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
@@ -15,6 +22,9 @@
|
||||
"minecraft:emitter_lifetime_looping": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0, -0.25]
|
||||
},
|
||||
|
||||
+10
@@ -8,6 +8,13 @@
|
||||
"texture": "textures/particles/bite"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.crunch.target"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
@@ -15,6 +22,9 @@
|
||||
"minecraft:emitter_lifetime_looping": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0, -0.25]
|
||||
},
|
||||
|
||||
+10
@@ -8,6 +8,13 @@
|
||||
"texture": "textures/particles/ember"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.ember.actor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 50,
|
||||
@@ -16,6 +23,9 @@
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.45
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": ["math.random(-0.41,0.41)*(v.emitter_age*3.5)", "math.random(-0.41,0.41)*(v.emitter_age*3.5)", "math.random(-0.35,0.35)-v.emitter_age*7"],
|
||||
"direction": ["math.random(-0.45,0.45)*(v.emitter_age*3)", "math.random(-0.45,0.45)*(v.emitter_age*3)", "math.random(-2.05,-0.55)"]
|
||||
|
||||
+10
@@ -8,6 +8,13 @@
|
||||
"texture": "textures/particles/ember"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.ember.target"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 220,
|
||||
@@ -16,6 +23,9 @@
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.2
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 0.3
|
||||
|
||||
+10
@@ -8,6 +8,13 @@
|
||||
"texture": "textures/particles/fang"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.hyperfang.target"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
@@ -15,6 +22,9 @@
|
||||
"minecraft:emitter_lifetime_looping": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0, -0.25]
|
||||
},
|
||||
|
||||
+10
@@ -8,6 +8,13 @@
|
||||
"texture": "textures/particles/spoon"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.kinesis.actor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
@@ -15,6 +22,9 @@
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0, "-1.1/math.clamp(q.entity_scale*1.1-0.1,1,3)"]
|
||||
},
|
||||
|
||||
+3
@@ -22,6 +22,9 @@
|
||||
"minecraft:emitter_lifetime_looping": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0.1, -0.2]
|
||||
},
|
||||
|
||||
+96
-62
@@ -1,63 +1,97 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:mudsport_target",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particles/mud_splash"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.mudsize": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [1, 1, 1, 1, 1, 1, 0.5, 0]
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.5
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0.04, 0],
|
||||
"direction": ["math.random(-10,10)*1.1", 10, "math.random(-10,10)*1.1"]
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 1
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(0,3)*90"
|
||||
},
|
||||
"minecraft:particle_initial_speed": "math.random(6.3,9.2)*0.4",
|
||||
"minecraft:particle_motion_dynamic": {
|
||||
"linear_acceleration": [0, -7, 0],
|
||||
"linear_drag_coefficient": 2
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["(0.2+(v.particle_random_1*0.1))*v.mudsize", "(0.2+(v.particle_random_1*0.1))*v.mudsize"],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 8,
|
||||
"texture_height": 56,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [8, 8],
|
||||
"step_UV": [0, 8],
|
||||
"frames_per_second": 12,
|
||||
"max_frame": 10
|
||||
}
|
||||
}
|
||||
},
|
||||
"minecraft:particle_motion_collision": {
|
||||
"collision_drag": 1.1,
|
||||
"coefficient_of_restitution": 0.3,
|
||||
"collision_radius": 0.01
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:mudsport_target",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particles/mud_splash"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.mudsize": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0.5,
|
||||
0
|
||||
]
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.5
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [
|
||||
0,
|
||||
0.04,
|
||||
0
|
||||
],
|
||||
"direction": [
|
||||
"math.random(-10,10)*1.1",
|
||||
10,
|
||||
"math.random(-10,10)*1.1"
|
||||
]
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 1
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(0,3)*90"
|
||||
},
|
||||
"minecraft:particle_initial_speed": "math.random(6.3,9.2)*0.4",
|
||||
"minecraft:particle_motion_dynamic": {
|
||||
"linear_acceleration": [
|
||||
0,
|
||||
-7,
|
||||
0
|
||||
],
|
||||
"linear_drag_coefficient": 2
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": [
|
||||
"(0.2+(v.particle_random_1*0.1))*v.mudsize",
|
||||
"(0.2+(v.particle_random_1*0.1))*v.mudsize"
|
||||
],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 8,
|
||||
"texture_height": 56,
|
||||
"flipbook": {
|
||||
"base_UV": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"size_UV": [
|
||||
8,
|
||||
8
|
||||
],
|
||||
"step_UV": [
|
||||
0,
|
||||
8
|
||||
],
|
||||
"frames_per_second": 12,
|
||||
"max_frame": 8,
|
||||
"loop": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minecraft:particle_motion_collision": {
|
||||
"collision_drag": 1.1,
|
||||
"coefficient_of_restitution": 0.3,
|
||||
"collision_radius": 0.01
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -8,6 +8,13 @@
|
||||
"texture": "textures/particles/psychicsend"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.psychic.actor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
@@ -18,6 +25,9 @@
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0, -0.3]
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 1
|
||||
},
|
||||
|
||||
-10
@@ -8,13 +8,6 @@
|
||||
"texture": "textures/particles/pursuit"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.pursuit.target"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 3,
|
||||
@@ -23,9 +16,6 @@
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.75
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0, "-0.3/math.clamp(q.entity_scale*1.1-0.1,1,9)"]
|
||||
},
|
||||
|
||||
+10
@@ -16,6 +16,13 @@
|
||||
"nodes": [0, 0.63, 0.9, 0.98, 1, 1, 1, 1]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.sing.actor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 3,
|
||||
@@ -24,6 +31,9 @@
|
||||
"minecraft:emitter_lifetime_looping": {
|
||||
"active_time": 2.75
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0, -0.15],
|
||||
"direction": ["math.sin(v.emitter_age*400)*2", "math.cos(v.emitter_age*390)*2", "math.random(-15,-10)"]
|
||||
|
||||
+10
@@ -16,6 +16,13 @@
|
||||
"nodes": [0, 0.66, 0.94, 1, 1, 1, 1, 1, 0.93, 0.66, 0]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.superfang.actor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 10,
|
||||
@@ -24,6 +31,9 @@
|
||||
"minecraft:emitter_lifetime_looping": {
|
||||
"active_time": 0.8
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_disc": {
|
||||
"offset": [0, "(0.2+(q.entity_height*1)-(q.entity_height*(v.particle_random_2*0.2)))/0.85", 0],
|
||||
"radius": "(q.entity_radius-(q.entity_radius*(v.particle_random_2*0.3)))/0.85",
|
||||
|
||||
+10
@@ -8,6 +8,13 @@
|
||||
"texture": "textures/particles/fang"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.superfang.target"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
@@ -15,6 +22,9 @@
|
||||
"minecraft:emitter_lifetime_looping": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_events": {
|
||||
"creation_event": "event_sound"
|
||||
},
|
||||
"minecraft:emitter_shape_point": {
|
||||
"offset": [0, 0, -0.25]
|
||||
},
|
||||
|
||||
+7
@@ -16,6 +16,13 @@
|
||||
"nodes": [1, 1, 1, 1, 1, 1, 0.5, 0]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"event_sound": {
|
||||
"sound_effect": {
|
||||
"event_name": "cobblemon:move.watersport.actor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 500,
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_bug_block"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_bug_budding"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_dark_block"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_dark_budding"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_dragon_block"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_dragon_budding"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_electric_block"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_electric_budding"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_fairy_block"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_fairy_budding"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_fighting_block"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_fighting_budding"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_fire_block"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_fire_budding"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "cobblemon:block/gem_flying_block"
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user