mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-11-15 12:48:53 -05:00
Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e94b5f775a | ||
|
|
069694c782 | ||
|
|
3ab78e0f0b | ||
|
|
acb2a6aeaa | ||
|
|
d5ea6e5494 | ||
|
|
99e0a26d7b | ||
|
|
71753df513 | ||
|
|
729f080f6e | ||
|
|
13eb57afb1 | ||
|
|
72b6cb06ff | ||
|
|
74a57eb972 | ||
|
|
7246c7f8e6 | ||
|
|
cd05f741ae | ||
|
|
00222d929d | ||
|
|
b8f4637cb3 | ||
|
|
9f572250f5 | ||
|
|
0927d6fa43 | ||
|
|
a293b3d71f | ||
|
|
162b1cc68f | ||
|
|
066a6b56f7 | ||
|
|
7687833add | ||
|
|
cb9ba82fcc | ||
|
|
4221993f7d | ||
|
|
a616c25c8c | ||
|
|
6ce4bf5673 | ||
|
|
1b652ba99f | ||
|
|
11b59df386 | ||
|
|
ac2b068bf3 | ||
|
|
8e8f346e52 |
No files matched your search
@@ -3,9 +3,17 @@
|
||||
|
||||
### Additions
|
||||
- Added the `healersSetSpawn` gamerule. When enabled, using a healing machine will set your spawnpoint.
|
||||
- A Pokémon holding a Power item now gains 1 point in the corresponding riding stat every two minutes while being ridden. The interval is configurable, and can be disabled with `-1`.
|
||||
- Added sounds to Gigaton Hammer and Pyro Ball
|
||||
- Added stepsounds to Venusaur, Blastoise, Dewgong, Rhydon, Rhyhorn, Parasect and Mr. Mime.
|
||||
- Added `cosmetic_item` command
|
||||
|
||||
### Changes
|
||||
- Amethyst now grows from Typegem core blocks like typegems do
|
||||
- Updated the recipe category for the Create compatibility EXP Candy recipe
|
||||
- Added No Man's Lands' Honeyed Apple to the Leaves Leftovers tag
|
||||
- Added lore support to held and cosmetic items
|
||||
- Pokemon can now wear every item with `cobblemon:aspect` component in their cosmetic slot
|
||||
|
||||
### Fixes
|
||||
- Fixed Ponigiri food values for AppleSkin integration
|
||||
@@ -17,6 +25,8 @@
|
||||
- `q.is_standing_on_blocks` now properly checks for non-full blocks like slabs, Mud or Soul Sand
|
||||
- Added Molang functions to play footstep sounds based on the corresponding surface. These are intended to be used by Pokémon animations.
|
||||
- Pokémon can now have their Minecraft footstep sounds silenced in their poser. This doesn't affect emitting game events.
|
||||
- Cosmetic items can now add aspects automatically to pokemon when wore. for example `cosmetic_minecraft-dirt-test` if pokemon wears a dirt block with `[cobblemon:aspect='test']` component
|
||||
- Held items can now add automatically aspects to pokemon when held. for example `held_minecraft-dirt` if pokemon holds a dirt block or `cosmetic_minecraft-dirt-test` if pokemon holds a dirt block with `[cobblemon:aspect='test']` component
|
||||
|
||||
### Particles
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ import com.cobblemon.mod.common.pokemon.aspects.ALPHA_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.HELD_ITEM_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.MARK_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
@@ -326,6 +327,7 @@ object Cobblemon {
|
||||
|
||||
SHINY_ASPECT.register()
|
||||
GENDER_ASPECT.register()
|
||||
HELD_ITEM_ASPECT.register()
|
||||
COSMETIC_SLOT_ASPECT.register()
|
||||
CHARACTERISTIC_RAINBOW_ASPECT.register()
|
||||
ALPHA_ASPECT.register()
|
||||
|
||||
@@ -39,6 +39,7 @@ object CobblemonCommands {
|
||||
FriendshipCommand.register(dispatcher)
|
||||
GiveAllPokemon.register(dispatcher)
|
||||
HeldItemCommand.register(dispatcher, registry)
|
||||
CosmeticItemCommand.register(dispatcher, registry)
|
||||
PcCommand.register(dispatcher)
|
||||
SpawnPokemonFromPool.register(dispatcher)
|
||||
PokeboxCommand.register(dispatcher)
|
||||
|
||||
@@ -77,15 +77,15 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
|
||||
@JvmField
|
||||
val INGREDIENT: DataComponentType<IngredientComponent> = create("ingredient", DataComponentType.builder<IngredientComponent>()
|
||||
.persistent(IngredientComponent.CODEC)
|
||||
.networkSynchronized(IngredientComponent.PACKET_CODEC)
|
||||
.build())
|
||||
.persistent(IngredientComponent.CODEC)
|
||||
.networkSynchronized(IngredientComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val FOOD: DataComponentType<FoodComponent> = create("food", DataComponentType.builder<FoodComponent>()
|
||||
.persistent(FoodComponent.CODEC)
|
||||
.networkSynchronized(FoodComponent.PACKET_CODEC)
|
||||
.build())
|
||||
.persistent(FoodComponent.CODEC)
|
||||
.networkSynchronized(FoodComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val MOB_EFFECTS: DataComponentType<MobEffectsComponent> = create("mob_effects", DataComponentType.builder<MobEffectsComponent>()
|
||||
@@ -95,9 +95,15 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
|
||||
@JvmField
|
||||
val CRAFTED: DataComponentType<Boolean> = create("crafted", DataComponentType.builder<Boolean>()
|
||||
.persistent(Codec.BOOL)
|
||||
.networkSynchronized(ByteBufCodecs.BOOL)
|
||||
.build())
|
||||
.persistent(Codec.BOOL)
|
||||
.networkSynchronized(ByteBufCodecs.BOOL)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val ASPECT: DataComponentType<BedrockAspectComponent> = create("aspect", DataComponentType.builder<BedrockAspectComponent>()
|
||||
.persistent(BedrockAspectComponent.CODEC)
|
||||
.networkSynchronized(BedrockAspectComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
fun register() {
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:pokemon_item"), POKEMON_ITEM)
|
||||
@@ -112,9 +118,9 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:mob_effects"), MOB_EFFECTS)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:held_item_effect"), HELD_ITEM_EFFECT)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:aspect"), ASPECT)
|
||||
}
|
||||
|
||||
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
|
||||
override val resourceKey = Registries.DATA_COMPONENT_TYPE
|
||||
|
||||
}
|
||||
}
|
||||
+3
-7
@@ -37,7 +37,6 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val HEAL_POKEMON_OTHER = this.create("$HEAL_POKEMON_BASE.other", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
|
||||
private const val LEVEL_UP_BASE = "${COMMAND_PREFIX}levelup"
|
||||
@JvmStatic
|
||||
val LEVEL_UP_SELF = this.create("$LEVEL_UP_BASE.self", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@@ -68,27 +67,24 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val SPAWN_NPC = this.create("${COMMAND_PREFIX}spawnnpc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
|
||||
@JvmStatic
|
||||
val STOP_BATTLE = this.create("${COMMAND_PREFIX}stopbattle", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
|
||||
@JvmStatic
|
||||
val TAKE_POKEMON = this.create("${COMMAND_PREFIX}takepokemon", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
|
||||
@JvmStatic
|
||||
val TEACH = this.create("${COMMAND_PREFIX}teach.base", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val TEACH_BYPASS_LEARNSET = this.create("${COMMAND_PREFIX}teach.bypass", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
|
||||
@JvmStatic
|
||||
val FRIENDSHIP = this.create("${COMMAND_PREFIX}friendship", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
|
||||
@JvmStatic
|
||||
val HELD_ITEM = this.create("${COMMAND_PREFIX}helditem", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val COSMETIC_ITEM = this.create("${COMMAND_PREFIX}cosmeticitem", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
val CHANGE_MARK = this.create("${COMMAND_PREFIX}changemark", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@@ -161,4 +157,4 @@ object CobblemonPermissions {
|
||||
return permission
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -26,6 +26,7 @@ import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.locale.Language
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.item.Items
|
||||
|
||||
fun describePokemonProperties(properties: PokemonProperties): MutableComponent? {
|
||||
@@ -57,7 +58,7 @@ fun describePokemonProperties(properties: PokemonProperties): MutableComponent?
|
||||
}
|
||||
|
||||
val heldItemDescriptor = properties.heldItem?.let { heldItem ->
|
||||
val itemId = heldItem.substringBefore('[').trim().asIdentifierDefaultingNamespace()
|
||||
val itemId = ResourceLocation.parse("minecraft:dirt")
|
||||
val item = BuiltInRegistries.ITEM.get(itemId)
|
||||
if (item == Items.AIR) null else lang("ui.pokedex.requirement.properties.held_item", item.description.plainCopy().green())
|
||||
}
|
||||
@@ -139,4 +140,4 @@ private fun describeStringSpeciesFeature(property: StringSpeciesFeature): Mutabl
|
||||
?: Component.literal(property.value)
|
||||
|
||||
return lang(key, value.green())
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import com.cobblemon.mod.common.pokemon.RenderablePokemon
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.adapters.RegistryAccessResolver
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.isDouble
|
||||
import com.cobblemon.mod.common.util.isFloat
|
||||
@@ -52,8 +53,11 @@ import java.util.UUID
|
||||
import kotlin.math.min
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.ResourceLocationException
|
||||
import net.minecraft.advancements.critereon.ItemPredicate
|
||||
import net.minecraft.commands.arguments.item.ItemInput
|
||||
import net.minecraft.commands.arguments.item.ItemParser
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.component.DataComponentPredicate
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
@@ -157,7 +161,8 @@ open class PokemonProperties {
|
||||
null
|
||||
}
|
||||
}
|
||||
props.heldItem = parseString(keyPairs, listOf("helditem", "held_item"))
|
||||
props.heldItem = parseItem(keyPairs, listOf("helditem", "held_item"))
|
||||
props.cosmeticItem = parseItem(keyPairs, listOf("cosmetic", "cosmeticitem", "cosmetic_item"))
|
||||
props.minPerfectIVs = parseIntProperty(keyPairs, listOf("min_perfect_ivs"))?.coerceIn(0, Stats.PERMANENT.size)
|
||||
props.scaleModifier = parseFloatProperty(keyPairs, listOf("scale_modifier"))
|
||||
|
||||
@@ -340,6 +345,20 @@ open class PokemonProperties {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun parseItem(keyPairs: MutableList<Pair<String, String?>>, labels: Iterable<String>): ItemStack? {
|
||||
val matched = getMatchedKeyPair(keyPairs, labels) ?: return null
|
||||
val value = matched.second?.lowercase() ?: return null
|
||||
return try {
|
||||
val parseResult = ItemParser(RegistryAccessResolver.getAccess())
|
||||
.parse(StringReader(value))
|
||||
val input = ItemInput(parseResult.item(), parseResult.components())
|
||||
|
||||
input.createItemStack(1, false)
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var originalString: String = ""
|
||||
@@ -366,8 +385,8 @@ open class PokemonProperties {
|
||||
var originalTrainer: String? = null // Original Trainer by Username or UUID
|
||||
var moves: List<String>? = null
|
||||
var movesetBuilders: List<ResourceLocation>? = null
|
||||
var heldItem: String? = null
|
||||
var cosmeticItem: String? = null
|
||||
var heldItem: ItemStack? = null
|
||||
var cosmeticItem: ItemStack? = null
|
||||
var scaleModifier: Float? = null
|
||||
var isAlpha: Boolean? = null
|
||||
|
||||
@@ -494,16 +513,14 @@ open class PokemonProperties {
|
||||
pokemon.initializeMovesetFrom(movesetBuilder)
|
||||
}
|
||||
}
|
||||
heldItem?.let { itemKey ->
|
||||
val server = server() ?: return@let
|
||||
val parser = ItemParser(server.registryAccess())
|
||||
val result = parser.parse(StringReader(itemKey))
|
||||
|
||||
val stack = ItemStack(result.item)
|
||||
stack.applyComponents(result.components)
|
||||
heldItem?.let { stack ->
|
||||
if (stack.isEmpty) return@let
|
||||
pokemon.swapHeldItem(stack, decrement = true, aiCanDrop = false)
|
||||
}
|
||||
cosmeticItem?.let { stack ->
|
||||
if (stack.isEmpty) return@let
|
||||
pokemon.swapCosmeticItem(stack, decrement = true)
|
||||
}
|
||||
scaleModifier?.let { pokemon.scaleModifier = it }
|
||||
pokemon.updateAspects()
|
||||
}
|
||||
@@ -564,21 +581,21 @@ open class PokemonProperties {
|
||||
originalTrainer?.takeIf { it != pokemon.originalTrainer }?.let { return false }
|
||||
originalTrainerType?.takeIf { it != pokemon.originalTrainerType }?.let { return false }
|
||||
moves?.takeIf { it.any { move -> pokemon.moveSet.none { it.template.name == move } } }?.let { return false }
|
||||
heldItem?.takeIf { itemKey ->
|
||||
val server = server() ?: return@takeIf true
|
||||
val parser = ItemParser(server.registryAccess())
|
||||
val result = parser.parse(StringReader(itemKey))
|
||||
heldItem?.takeIf { stack ->
|
||||
val predicate = ItemPredicate.Builder.item()
|
||||
.of(pokemon.heldItem.item)
|
||||
.hasComponents(DataComponentPredicate.allOf(pokemon.heldItem.components))
|
||||
.build()
|
||||
|
||||
if (!pokemon.heldItem.`is`(result.item)) return@takeIf true
|
||||
return@takeIf !predicate.test(stack)
|
||||
}?.let { return false }
|
||||
cosmeticItem?.takeIf { stack ->
|
||||
val predicate = ItemPredicate.Builder.item()
|
||||
.of(pokemon.heldItem.item)
|
||||
.hasComponents(DataComponentPredicate.allOf(pokemon.heldItem.components))
|
||||
.build()
|
||||
|
||||
for (entry in result.components.entrySet()) {
|
||||
val targetPropValue = pokemon.heldItem.get(entry.key)
|
||||
if (targetPropValue != entry.value.get()) {
|
||||
return@takeIf true
|
||||
}
|
||||
}
|
||||
|
||||
return@takeIf false
|
||||
return@takeIf !predicate.test(stack)
|
||||
}?.let { return false }
|
||||
scaleModifier?.takeIf { it != pokemon.scaleModifier }?.let { return false }
|
||||
return true
|
||||
@@ -706,7 +723,14 @@ open class PokemonProperties {
|
||||
originalTrainer?.let { nbt.putString(DataKeys.POKEMON_ORIGINAL_TRAINER, it) }
|
||||
moves?.let { nbt.putString(DataKeys.POKEMON_PROPERTIES_MOVES, it.joinToString(separator = ",")) }
|
||||
movesetBuilders?.let { nbt.putString(DataKeys.POKEMON_PROPERTIES_MOVESET_BUILDERS, it.joinToString(separator = ",") { source -> source.toString() }) }
|
||||
heldItem?.let {nbt.putString(DataKeys.POKEMON_PROPERTIES_HELDITEM, it)}
|
||||
heldItem?.let {
|
||||
val tag = ItemStack.SINGLE_ITEM_CODEC.encodeStart(NbtOps.INSTANCE, it)
|
||||
nbt.put(DataKeys.POKEMON_PROPERTIES_HELDITEM, tag.orThrow)
|
||||
}
|
||||
cosmeticItem?.let {
|
||||
val tag = ItemStack.SINGLE_ITEM_CODEC.encodeStart(NbtOps.INSTANCE, it)
|
||||
nbt.put(DataKeys.POKEMON_PROPERTIES_COSMETICITEM, tag.orThrow)
|
||||
}
|
||||
scaleModifier?.let { nbt.putFloat(DataKeys.POKEMON_SCALE_MODIFIER, it) }
|
||||
val custom = ListTag()
|
||||
customProperties.map { StringTag.valueOf(it.asString()) }.forEach { custom.add(it) }
|
||||
@@ -742,8 +766,16 @@ open class PokemonProperties {
|
||||
originalTrainer = if (tag.contains(DataKeys.POKEMON_ORIGINAL_TRAINER)) tag.getString(DataKeys.POKEMON_ORIGINAL_TRAINER) else null
|
||||
moves = if (tag.contains(DataKeys.POKEMON_PROPERTIES_MOVES)) tag.getString(DataKeys.POKEMON_PROPERTIES_MOVES).split(",") else null
|
||||
movesetBuilders = if (tag.contains(DataKeys.POKEMON_PROPERTIES_MOVESET_BUILDERS)) tag.getString(DataKeys.POKEMON_PROPERTIES_MOVESET_BUILDERS).split(",").map { it.asIdentifierDefaultingNamespace() } else null
|
||||
heldItem = if (tag.contains(DataKeys.POKEMON_PROPERTIES_HELDITEM)) tag.getString(DataKeys.POKEMON_PROPERTIES_HELDITEM) else null
|
||||
scaleModifier = if (tag.contains(DataKeys.POKEMON_SCALE_MODIFIER)) tag.getFloat(DataKeys.POKEMON_SCALE_MODIFIER) else null
|
||||
heldItem = when(tag.contains(DataKeys.POKEMON_PROPERTIES_HELDITEM)) {
|
||||
true -> ItemStack.parse(RegistryAccessResolver.getAccess(), tag.get(DataKeys.POKEMON_PROPERTIES_HELDITEM)!!).getOrNull()
|
||||
false -> null
|
||||
}
|
||||
cosmeticItem = when(tag.contains(DataKeys.POKEMON_PROPERTIES_COSMETICITEM)) {
|
||||
true -> ItemStack.parse(RegistryAccessResolver.getAccess(), tag.get(DataKeys.POKEMON_PROPERTIES_COSMETICITEM)!!).getOrNull()
|
||||
false -> null
|
||||
}
|
||||
|
||||
val custom = tag.getList(DataKeys.POKEMON_PROPERTIES_CUSTOM, Tag.TAG_STRING.toInt())
|
||||
// This is kinda gross
|
||||
custom.forEach { customProperties.addAll(parse(it.asString).customProperties) }
|
||||
@@ -780,7 +812,18 @@ open class PokemonProperties {
|
||||
originalTrainer?.let { json.addProperty(DataKeys.POKEMON_ORIGINAL_TRAINER, it) }
|
||||
moves?.let { json.addProperty(DataKeys.POKEMON_PROPERTIES_MOVES, it.joinToString(separator = ",")) }
|
||||
movesetBuilders?.let { json.addProperty(DataKeys.POKEMON_PROPERTIES_MOVESET_BUILDERS, it.joinToString(separator = ",") { source -> source.toString() }) }
|
||||
heldItem?.let {json.addProperty(DataKeys.POKEMON_PROPERTIES_HELDITEM, it)}
|
||||
heldItem?.let {
|
||||
json.add(
|
||||
DataKeys.POKEMON_PROPERTIES_HELDITEM,
|
||||
ItemStack.SINGLE_ITEM_CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()
|
||||
)
|
||||
}
|
||||
cosmeticItem?.let {
|
||||
json.add(
|
||||
DataKeys.POKEMON_PROPERTIES_COSMETICITEM,
|
||||
ItemStack.SINGLE_ITEM_CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()
|
||||
)
|
||||
}
|
||||
scaleModifier?.let { json.addProperty(DataKeys.POKEMON_SCALE_MODIFIER, it) }
|
||||
val custom = JsonArray()
|
||||
customProperties.map { it.asString() }.forEach { custom.add(it) }
|
||||
@@ -817,7 +860,12 @@ open class PokemonProperties {
|
||||
originalTrainer = json.get(DataKeys.POKEMON_ORIGINAL_TRAINER)?.asString
|
||||
moves = json.get(DataKeys.POKEMON_PROPERTIES_MOVES)?.asString?.split(",")
|
||||
movesetBuilders = json.get(DataKeys.POKEMON_PROPERTIES_MOVESET_BUILDERS)?.asString?.split(",")?.map { it.asIdentifierDefaultingNamespace() }
|
||||
heldItem = json.get(DataKeys.POKEMON_PROPERTIES_HELDITEM)?.asString
|
||||
heldItem = json.getAsJsonObject(DataKeys.POKEMON_PROPERTIES_HELDITEM)?.let {
|
||||
ItemStack.SINGLE_ITEM_CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first
|
||||
}
|
||||
cosmeticItem = json.getAsJsonObject(DataKeys.POKEMON_PROPERTIES_COSMETICITEM)?.let {
|
||||
ItemStack.SINGLE_ITEM_CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first
|
||||
}
|
||||
scaleModifier = json.get(DataKeys.POKEMON_SCALE_MODIFIER)?.asFloat
|
||||
val custom = json.get(DataKeys.POKEMON_PROPERTIES_CUSTOM)?.asJsonArray
|
||||
// This is still kinda gross
|
||||
@@ -859,6 +907,7 @@ open class PokemonProperties {
|
||||
moves?.let { pieces.add("moves=${it.joinToString(separator = ",")}") }
|
||||
movesetBuilders?.let { pieces.add("movesetbuilders=${it.joinToString(separator = ",") { source -> source.toString() }}") }
|
||||
heldItem?.let {pieces.add("helditem=$it")}
|
||||
cosmeticItem?.let {pieces.add("cosmeticitem=$it")}
|
||||
scaleModifier?.let { pieces.add("scale_modifier=$it") }
|
||||
return pieces.joinToString(separator)
|
||||
}
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
package com.cobblemon.mod.common.api.riding.stats
|
||||
|
||||
import com.cobblemon.mod.common.api.cooking.Flavour
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.item.Item
|
||||
|
||||
/**
|
||||
* A stat that is used for riding Pokémon. The exact implementation of each of these depends on the [com.cobblemon.mod.common.api.riding.controller.RideController].
|
||||
@@ -20,13 +23,14 @@ import net.minecraft.network.chat.MutableComponent
|
||||
* @since February 17th, 2025
|
||||
*/
|
||||
enum class RidingStat(
|
||||
val flavour: Flavour
|
||||
val flavour: Flavour,
|
||||
val powerItem: TagKey<Item>
|
||||
) {
|
||||
ACCELERATION(Flavour.SPICY),
|
||||
SKILL(Flavour.DRY),
|
||||
SPEED(Flavour.SWEET),
|
||||
STAMINA(Flavour.SOUR),
|
||||
JUMP(Flavour.BITTER);
|
||||
ACCELERATION(Flavour.SPICY, CobblemonItemTags.POWER_BRACER),
|
||||
SKILL(Flavour.DRY, CobblemonItemTags.POWER_BELT),
|
||||
SPEED(Flavour.SWEET, CobblemonItemTags.POWER_ANKLET),
|
||||
STAMINA(Flavour.SOUR, CobblemonItemTags.POWER_WEIGHT),
|
||||
JUMP(Flavour.BITTER, CobblemonItemTags.POWER_BAND);
|
||||
|
||||
companion object {
|
||||
fun getByName(name: String) = RidingStat.entries.firstOrNull { it.name.equals(name, ignoreCase = true) }
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.command
|
||||
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
|
||||
import com.cobblemon.mod.common.util.commandLang
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.commands.CommandBuildContext
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands.argument
|
||||
import net.minecraft.commands.Commands.literal
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
import net.minecraft.commands.arguments.item.ItemArgument
|
||||
|
||||
object CosmeticItemCommand {
|
||||
|
||||
private const val NAME = "cosmetic_item"
|
||||
private const val TARGET = "target"
|
||||
private const val SLOT = "slot"
|
||||
private const val ITEM = "item"
|
||||
|
||||
fun register(dispatcher: CommandDispatcher<CommandSourceStack>, commandRegistryAccess: CommandBuildContext) {
|
||||
dispatcher.register(literal(NAME)
|
||||
.permission(CobblemonPermissions.COSMETIC_ITEM)
|
||||
.then(argument(TARGET, EntityArgument.player())
|
||||
.then(argument(SLOT, PartySlotArgumentType.partySlot())
|
||||
.then(argument(ITEM, ItemArgument.item(commandRegistryAccess))
|
||||
.executes(this::execute)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun execute(ctx: CommandContext<CommandSourceStack>): Int {
|
||||
val player = EntityArgument.getPlayer(ctx, TARGET)
|
||||
val pokemon = PartySlotArgumentType.getPokemonOf(ctx, SLOT, player)
|
||||
val stackArgument = ItemArgument.getItem(ctx, ITEM)
|
||||
val stack = stackArgument.createItemStack(1, false)
|
||||
pokemon.swapCosmeticItem(stack, true)
|
||||
ctx.source.sendSuccess({ commandLang(NAME, player.name, pokemon.species.translatedName, stack.displayName) }, true)
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,6 +47,10 @@ class CobblemonConfig {
|
||||
@IntConstraint(min = 0, max = 1000)
|
||||
var maxPokemonFriendship = 255
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "power_item_ride_stat_gain_interval_seconds", SERVER)
|
||||
@IntConstraint(min = -1, max = Int.MAX_VALUE)
|
||||
var powerItemRideStatGainIntervalSeconds = 120
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "announce_drop_items", SERVER)
|
||||
var announceDropItems = true
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "default_drop_item_method", SERVER)
|
||||
|
||||
@@ -107,6 +107,7 @@ import com.cobblemon.mod.common.pokemon.feature.SlowpokeTailRegrowthSpeciesFeatu
|
||||
import com.cobblemon.mod.common.pokemon.feature.StashHandler
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.adapters.RegistryAccessResolver
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import com.google.common.collect.UnmodifiableIterator
|
||||
@@ -1296,17 +1297,11 @@ open class PokemonEntity(
|
||||
private fun showInteractionWheel(player: ServerPlayer, itemStack: ItemStack) {
|
||||
val canRide = isRideableFor(player)
|
||||
if (pokemon.getOwnerPlayer() == player) {
|
||||
val cosmeticItemDefinition = CobblemonCosmeticItems.findValidCosmeticForPokemonAndItem(
|
||||
player.level().registryAccess(),
|
||||
pokemon,
|
||||
itemStack
|
||||
)
|
||||
|
||||
InteractPokemonUIPacket(
|
||||
this.getUUID(),
|
||||
canSitOnShoulder() && pokemon in player.party(),
|
||||
!(pokemon.heldItemNoCopy().isEmpty && itemStack.isEmpty),
|
||||
(!pokemon.cosmeticItem.isEmpty && itemStack.isEmpty) || cosmeticItemDefinition != null,
|
||||
canGiveCosmetic(itemStack),
|
||||
canRide
|
||||
).sendToPlayer(player)
|
||||
}
|
||||
@@ -1328,6 +1323,17 @@ open class PokemonEntity(
|
||||
return@canRide behaviour.isActive(settings, state, this)
|
||||
}
|
||||
|
||||
fun canGiveCosmetic(itemStack: ItemStack): Boolean {
|
||||
val cosmeticItemDefinition = CobblemonCosmeticItems.findValidCosmeticForPokemonAndItem(
|
||||
RegistryAccessResolver.getAccess(),
|
||||
pokemon,
|
||||
itemStack
|
||||
)
|
||||
|
||||
return (!pokemon.cosmeticItem().isEmpty && itemStack.isEmpty)
|
||||
|| (itemStack.has(CobblemonItemComponents.ASPECT) || cosmeticItemDefinition != null)
|
||||
}
|
||||
|
||||
override fun getDimensions(pose: Pose): EntityDimensions {
|
||||
val scale = effects.mockEffect?.scale ?: (form.baseScale * pokemon.effectiveScale)
|
||||
var result = this.exposedForm.hitbox.scale(scale)
|
||||
@@ -1560,7 +1566,7 @@ open class PokemonEntity(
|
||||
return false
|
||||
}
|
||||
|
||||
val possibleReturn = if (isCosmetic) this.pokemon.cosmeticItem.copy() else this.pokemon.heldItemNoCopy()
|
||||
val possibleReturn = if (isCosmetic) this.pokemon.cosmeticItem() else this.pokemon.heldItemNoCopy()
|
||||
val giving = stack.copy().apply { count = 1 }
|
||||
|
||||
if (ItemStack.isSameItemSameComponents(giving, possibleReturn)) {
|
||||
@@ -2749,4 +2755,4 @@ open class PokemonEntity(
|
||||
if (this.pokemon.species.silenceStepSounds) return
|
||||
super.playStepSound(pos, state)
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.TickingSpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause.Companion.DROPS_REROLL_ASPECT
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
@@ -46,10 +47,15 @@ import kotlin.math.*
|
||||
|
||||
/** Handles purely server logic for a Pokémon */
|
||||
class PokemonServerDelegate : PokemonSideDelegate {
|
||||
companion object {
|
||||
private const val RIDE_STAT_GAIN_AMOUNT = 1F
|
||||
}
|
||||
|
||||
lateinit var entity: PokemonEntity
|
||||
var acknowledgedHPValue = -1
|
||||
var acknowledgedLevel = -1
|
||||
val passengerOffsets = mutableMapOf<Int, Vec3>()
|
||||
private var rideStatGainAnchor: Vec3? = null
|
||||
|
||||
/** Mocked properties exposed to the client [PokemonEntity]. */
|
||||
private val mock: PokemonProperties?
|
||||
@@ -355,9 +361,30 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
val rideStatGainIntervalSeconds = Cobblemon.config.powerItemRideStatGainIntervalSeconds
|
||||
if (rideStatGainIntervalSeconds > 0) {
|
||||
val rideStatGainIntervalTicks = rideStatGainIntervalSeconds * 20L
|
||||
if (entity.level().gameTime % rideStatGainIntervalTicks == 0L) {
|
||||
trainRideStats()
|
||||
}
|
||||
}
|
||||
|
||||
updateTrackedValues()
|
||||
}
|
||||
|
||||
private fun trainRideStats() {
|
||||
val position = entity.position()
|
||||
val anchor = rideStatGainAnchor
|
||||
rideStatGainAnchor = position
|
||||
if (anchor == null || anchor == position || entity.passengers.isEmpty()) return
|
||||
|
||||
val heldItem = entity.pokemon.heldItemNoCopy()
|
||||
if (heldItem.isEmpty) return
|
||||
|
||||
val stat = RidingStat.entries.firstOrNull { heldItem.`is`(it.powerItem) } ?: return
|
||||
entity.pokemon.addRideBoost(stat, RIDE_STAT_GAIN_AMOUNT)
|
||||
}
|
||||
|
||||
fun updateShownItem() {
|
||||
val trackedShownItem = when {
|
||||
// Show Hand Item if Held item is hidden
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.item.components
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.util.adapters.RegistryAccessResolver
|
||||
import com.mojang.serialization.Codec
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.util.StringRepresentable
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import java.util.Locale.getDefault
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
class BedrockAspectComponent(val aspect: String) {
|
||||
enum class Type: StringRepresentable {
|
||||
HELD,
|
||||
COSMETIC;
|
||||
|
||||
override fun toString(): String = name.lowercase(getDefault())
|
||||
override fun getSerializedName(): String = name.lowercase(getDefault())
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<BedrockAspectComponent> = Codec.STRING.xmap(
|
||||
{ aspect -> BedrockAspectComponent(aspect) },
|
||||
{ component -> component.aspect }
|
||||
)
|
||||
|
||||
val PACKET_CODEC: StreamCodec<ByteBuf, BedrockAspectComponent> = ByteBufCodecs.fromCodec(CODEC)
|
||||
|
||||
fun getAspect(stack: ItemStack, type: Type): String {
|
||||
val identifier = RegistryAccessResolver.getAccess()
|
||||
.registry(Registries.ITEM)
|
||||
.getOrNull()
|
||||
?.getResourceKey(stack.item)
|
||||
?.getOrNull()
|
||||
?.location()
|
||||
?.toString()
|
||||
?: "minecraft:dirt"
|
||||
|
||||
val item = identifier.replace("\\W".toRegex(), "-")
|
||||
|
||||
return when (stack.has(CobblemonItemComponents.ASPECT)) {
|
||||
true -> {
|
||||
val aspect = stack[CobblemonItemComponents.ASPECT]!!.aspect.replace("\\W".toRegex(), "-")
|
||||
"${type}_${item}-${aspect}"
|
||||
}
|
||||
false -> "${type}_$item"
|
||||
}
|
||||
}
|
||||
|
||||
fun setAspect(stack: ItemStack, aspect: String) = stack.also {
|
||||
it.set(CobblemonItemComponents.ASPECT, BedrockAspectComponent(aspect))
|
||||
}
|
||||
|
||||
fun createStack(item: Item, aspect: String): ItemStack = item.defaultInstance.also {
|
||||
setAspect(it, aspect)
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-4
@@ -22,9 +22,7 @@ class CosmeticItemUpdatePacket(pokemon: () -> Pokemon?, value: ItemStack) : Sing
|
||||
buffer.writeItemStack(this.value)
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: ItemStack) {
|
||||
pokemon.cosmeticItem = value
|
||||
}
|
||||
override fun set(pokemon: Pokemon, value: ItemStack) { pokemon.swapCosmeticItem(this.value, false) }
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("cosmetic_item_update")
|
||||
@@ -34,4 +32,4 @@ class CosmeticItemUpdatePacket(pokemon: () -> Pokemon?, value: ItemStack) : Sing
|
||||
return CosmeticItemUpdatePacket(pokemon, cosmeticItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -34,4 +34,4 @@ class HeldItemUpdatePacket(pokemon: () -> Pokemon?, value: ItemStack): SingleUpd
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,7 @@ import com.cobblemon.mod.common.entity.PlatformType
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
|
||||
import com.cobblemon.mod.common.item.components.BedrockAspectComponent
|
||||
import com.cobblemon.mod.common.net.messages.client.PokemonUpdatePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
|
||||
@@ -159,6 +160,7 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.MobSpawnType
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.CactusBlock
|
||||
import net.minecraft.world.level.block.CampfireBlock
|
||||
@@ -1290,20 +1292,23 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
fun swapHeldItem(stack: ItemStack, decrement: Boolean = true, aiCanDrop: Boolean = true): ItemStack {
|
||||
val existing = this.heldItem()
|
||||
val event = HeldItemEvent.Pre(this, stack, existing, decrement)
|
||||
if (!isClient) {
|
||||
CobblemonEvents.HELD_ITEM_PRE.post(event)
|
||||
}
|
||||
|
||||
if (!isClient) CobblemonEvents.HELD_ITEM_PRE.post(event)
|
||||
|
||||
if (!event.isCanceled) {
|
||||
val giving = event.receiving.copy().apply { count = 1 }
|
||||
if (event.decrement) {
|
||||
event.receiving.shrink(1)
|
||||
}
|
||||
this.heldItem = giving
|
||||
this.canDropHeldItem = giving.isEmpty || aiCanDrop
|
||||
onChange(HeldItemUpdatePacket({ this }, giving))
|
||||
this.heldItem = event.receiving.copy()
|
||||
.apply { count = 1 }
|
||||
.also { if (event.decrement) event.receiving.shrink(1) }
|
||||
|
||||
this.canDropHeldItem = this.heldItem.isEmpty || aiCanDrop
|
||||
|
||||
onChange(HeldItemUpdatePacket({ this }, this.heldItem()))
|
||||
CobblemonEvents.HELD_ITEM_POST.post(HeldItemEvent.Post(this, this.heldItem(), event.returning.copy(), event.decrement)) {
|
||||
StashHandler.giveHeldItem(it)
|
||||
}
|
||||
|
||||
updateAspects()
|
||||
|
||||
return event.returning
|
||||
}
|
||||
return stack
|
||||
@@ -1332,16 +1337,18 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
fun swapCosmeticItem(stack: ItemStack, decrement: Boolean = true): ItemStack {
|
||||
val existing = this.cosmeticItem.copy()
|
||||
val event = HeldItemEvent.Pre(this, stack, existing, decrement)
|
||||
if (!isClient) {
|
||||
CobblemonEvents.COSMETIC_ITEM_PRE.post(event)
|
||||
}
|
||||
|
||||
if (!isClient) CobblemonEvents.COSMETIC_ITEM_PRE.post(event)
|
||||
|
||||
if (!event.isCanceled) {
|
||||
val giving = event.receiving.copy().apply { count = 1 }
|
||||
if (event.decrement) {
|
||||
event.receiving.shrink(1)
|
||||
}
|
||||
this.cosmeticItem = giving
|
||||
CobblemonEvents.COSMETIC_ITEM_POST.post(HeldItemEvent.Post(this, this.cosmeticItem.copy(), event.returning.copy(), event.decrement))
|
||||
this.cosmeticItem = event.receiving.copy()
|
||||
.apply { count = 1 }
|
||||
.also { if (event.decrement) event.receiving.shrink(1) }
|
||||
|
||||
CobblemonEvents.COSMETIC_ITEM_POST.post(HeldItemEvent.Post(this, this.cosmeticItem(), event.returning.copy(), event.decrement))
|
||||
|
||||
updateAspects()
|
||||
|
||||
return event.returning
|
||||
}
|
||||
return stack
|
||||
|
||||
@@ -8,18 +8,17 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.aspects
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonCosmeticItems
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.SingleConditionalAspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.item.components.BedrockAspectComponent
|
||||
import com.cobblemon.mod.common.pokemon.Characteristic
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.Nature
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.adapters.RegistryAccessResolver
|
||||
import com.cobblemon.mod.common.util.server
|
||||
|
||||
val SHINY_ASPECT = object : SingleConditionalAspectProvider {
|
||||
@@ -43,12 +42,35 @@ val GENDER_ASPECT = object : AspectProvider {
|
||||
|
||||
val COSMETIC_SLOT_ASPECT = object : AspectProvider {
|
||||
override fun provide(pokemon: Pokemon): Set<String> {
|
||||
val server = server() ?: return emptySet()
|
||||
server() ?: return emptySet()
|
||||
|
||||
if (pokemon.cosmeticItem.isEmpty) {
|
||||
return emptySet()
|
||||
}
|
||||
val cosmeticItem = CobblemonCosmeticItems.findValidCosmeticForPokemonAndItem(server.registryAccess(), pokemon, pokemon.cosmeticItem)
|
||||
return cosmeticItem?.aspects?.toSet() ?: emptySet()
|
||||
|
||||
val cosmeticItemAspectSet = CobblemonCosmeticItems.findValidCosmeticForPokemonAndItem(
|
||||
RegistryAccessResolver.getAccess(),
|
||||
pokemon,
|
||||
pokemon.cosmeticItem
|
||||
)?.aspects?.toSet() ?: emptySet()
|
||||
|
||||
val stackAspect = BedrockAspectComponent.getAspect(pokemon.cosmeticItem, BedrockAspectComponent.Type.COSMETIC)
|
||||
|
||||
return setOf(stackAspect).plus(cosmeticItemAspectSet)
|
||||
}
|
||||
|
||||
override fun provide(properties: PokemonProperties) = emptySet<String>()
|
||||
}
|
||||
|
||||
val HELD_ITEM_ASPECT = object : AspectProvider {
|
||||
override fun provide(pokemon: Pokemon): Set<String> {
|
||||
server() ?: return emptySet()
|
||||
|
||||
if (pokemon.heldItem.isEmpty) {
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
return setOf(BedrockAspectComponent.getAspect(pokemon.heldItem, BedrockAspectComponent.Type.HELD))
|
||||
}
|
||||
|
||||
override fun provide(properties: PokemonProperties) = emptySet<String>()
|
||||
@@ -118,18 +140,18 @@ val CHARACTERISTIC_RAINBOW_ASPECT = object : AspectProvider {
|
||||
-> "rainbow-green"
|
||||
|
||||
(Stats.SPECIAL_DEFENCE to Stats.SPECIAL_ATTACK),
|
||||
(Stats.SPECIAL_ATTACK to Stats.SPECIAL_DEFENCE)
|
||||
(Stats.SPECIAL_ATTACK to Stats.SPECIAL_DEFENCE)
|
||||
-> "rainbow-cyan"
|
||||
|
||||
(Stats.SPECIAL_ATTACK to Stats.SPECIAL_ATTACK),
|
||||
(Stats.SPECIAL_ATTACK to Stats.HP),
|
||||
(null to Stats.SPECIAL_ATTACK),
|
||||
(Stats.SPECIAL_DEFENCE to Stats.SPEED),
|
||||
(Stats.SPEED to Stats.SPECIAL_DEFENCE)
|
||||
(Stats.SPEED to Stats.SPECIAL_DEFENCE)
|
||||
-> "rainbow-blue"
|
||||
|
||||
(Stats.SPECIAL_ATTACK to Stats.SPEED),
|
||||
(Stats.SPEED to Stats.SPECIAL_ATTACK)
|
||||
(Stats.SPEED to Stats.SPECIAL_ATTACK)
|
||||
-> "rainbow-purple"
|
||||
|
||||
(Stats.SPEED to Stats.SPEED),
|
||||
@@ -143,7 +165,7 @@ val CHARACTERISTIC_RAINBOW_ASPECT = object : AspectProvider {
|
||||
(Stats.ATTACK to Stats.SPEED),
|
||||
-> "rainbow-pink"
|
||||
|
||||
(null to Stats.HP)
|
||||
(null to Stats.HP)
|
||||
-> "rainbow-light-blue"
|
||||
|
||||
else -> null
|
||||
|
||||
@@ -14,20 +14,22 @@ import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.adapters.RegistryAccessResolver
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
object StashHandler {
|
||||
fun interactMob(player: Player, pokemon: Pokemon, itemStack: ItemStack?): Boolean {
|
||||
if (itemStack == null || player !is ServerPlayer|| pokemon.getOwnerPlayer() !== player) return false
|
||||
|
||||
val success = handleItem(pokemon, itemStack.item)
|
||||
if (success) {
|
||||
itemStack.shrink(1)
|
||||
}
|
||||
return success
|
||||
|
||||
return success.also { if (it) itemStack.shrink(1) }
|
||||
}
|
||||
|
||||
fun giveHeldItem(event: HeldItemEvent.Post) {
|
||||
@@ -40,11 +42,19 @@ object StashHandler {
|
||||
}
|
||||
|
||||
fun handleItem(pokemon: Pokemon, item: Item): Boolean {
|
||||
val itemIdentifier: ResourceLocation = item.builtInRegistryHolder().key().location()
|
||||
val itemIdentifier: ResourceLocation = RegistryAccessResolver.getAccess()
|
||||
.registry(Registries.ITEM)
|
||||
.get()
|
||||
.getResourceKey(item)
|
||||
.get()
|
||||
.location()
|
||||
|
||||
val speciesFeatureProviders = SpeciesFeatures.getFeaturesFor(pokemon.species)
|
||||
val relevantSpeciesFeatureProviders: List<IntSpeciesFeatureProvider> = speciesFeatureProviders.filter {
|
||||
it is IntSpeciesFeatureProvider && it.itemPoints.keys.contains(itemIdentifier)
|
||||
}.map { it as IntSpeciesFeatureProvider }
|
||||
|
||||
val relevantSpeciesFeatureProviders: List<IntSpeciesFeatureProvider> = speciesFeatureProviders
|
||||
.filter { it is IntSpeciesFeatureProvider && it.itemPoints.keys.contains(itemIdentifier) }
|
||||
.map { it as IntSpeciesFeatureProvider }
|
||||
|
||||
for (relevantSpeciesFeatureProvider in relevantSpeciesFeatureProviders) {
|
||||
val points = relevantSpeciesFeatureProvider.itemPoints[itemIdentifier]!!
|
||||
val feature = pokemon.getFeature<IntSpeciesFeature>(relevantSpeciesFeatureProvider.keys[0])!!
|
||||
@@ -52,9 +62,11 @@ object StashHandler {
|
||||
pokemon.markFeatureDirty(feature)
|
||||
if (feature.value > relevantSpeciesFeatureProvider.max) feature.value = relevantSpeciesFeatureProvider.max
|
||||
}
|
||||
if (relevantSpeciesFeatureProviders.isNotEmpty()) {
|
||||
if (pokemon.entity != null) pokemon.entity!!.playSound(CobblemonSounds.GIMMIGHOUL_GIVE_ITEM, 1f, 1f)
|
||||
|
||||
if (relevantSpeciesFeatureProviders.isNotEmpty() && pokemon.entity != null) {
|
||||
pokemon.entity!!.playSound(CobblemonSounds.GIMMIGHOUL_GIVE_ITEM, 1f, 1f)
|
||||
}
|
||||
|
||||
return relevantSpeciesFeatureProviders.isNotEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -24,6 +24,7 @@ import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionReg
|
||||
import com.cobblemon.mod.common.pokemon.EVs
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.cosmetic.CosmeticItemDefinition
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.simplify
|
||||
@@ -151,6 +152,7 @@ internal object PropertiesCompletionProvider : DataRegistry {
|
||||
this.inject(setOf("originaltrainertype", "ottype"), setOf("None", "Player", "NPC"))
|
||||
this.inject(setOf("nickname", "nick"), setOf(""))
|
||||
this.inject(setOf("helditem", "held_item"), setOf("cobblemon:exp_share"))
|
||||
this.inject(setOf("cosmetic", "cosmeticitem", "cosmetic_item"), setOf("cobblemon:exp_share"))
|
||||
this.inject(setOf("min_perfect_ivs"), setOf("0", "6"))
|
||||
this.inject(setOf("scale_modifier"), setOf("0.5", "2.0"))
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ object DataKeys {
|
||||
|
||||
const val POKEMON_PROPERTIES_MOVES = "Moves"
|
||||
const val POKEMON_PROPERTIES_HELDITEM = "HeldItem"
|
||||
const val POKEMON_PROPERTIES_COSMETICITEM = "CosmeticItem"
|
||||
const val POKEMON_PROPERTIES_MOVESET_BUILDERS = "MovesetBuilders"
|
||||
|
||||
// Entity effects
|
||||
|
||||
+837
-649
File diff suppressed because it is too large.
Load diff
+6
@@ -456,6 +456,12 @@
|
||||
"cannon_left": {
|
||||
"position": [0, 0, 3]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.25": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"1.25": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"2.25": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"3.25": "q.run_molang('cobblemon:stepsound_standard_large');"
|
||||
}
|
||||
},
|
||||
"animation.blastoise.ground_run": {
|
||||
|
||||
+11
@@ -83,6 +83,7 @@
|
||||
},
|
||||
"animation.parasect.ground_walk": {
|
||||
"loop": true,
|
||||
"animation_length": 1,
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [0, 0, 0],
|
||||
@@ -134,6 +135,12 @@
|
||||
"locator_seat_1": {
|
||||
"rotation": [7.5, 0, 0]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.run_molang('cobblemon:stepsound_minecraft');",
|
||||
"0.25": "q.run_molang('cobblemon:stepsound_minecraft');",
|
||||
"0.5": "q.run_molang('cobblemon:stepsound_minecraft');",
|
||||
"0.75": "q.run_molang('cobblemon:stepsound_minecraft');"
|
||||
}
|
||||
},
|
||||
"animation.parasect.ground_run": {
|
||||
@@ -258,6 +265,10 @@
|
||||
"rotation": ["5+Math.cos((query.anim_time) * 90 * 16 - 90) * 2", 0, 0],
|
||||
"position": [0, "0+Math.cos((query.anim_time) * 90 * 32) * -0.2", -0.25]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.run_molang('cobblemon:stepsound_minecraft');",
|
||||
"0.125": "q.run_molang('cobblemon:stepsound_minecraft');"
|
||||
}
|
||||
},
|
||||
"animation.parasect.ride_ground_run": {
|
||||
|
||||
+4
@@ -391,6 +391,10 @@
|
||||
"0.7083": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0833": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"0.2917": "q.run_molang('cobblemon:stepsound_standard_medium');"
|
||||
}
|
||||
},
|
||||
"animation.dewgong.water_idle": {
|
||||
|
||||
+20
@@ -1071,6 +1071,16 @@
|
||||
"head": {
|
||||
"rotation": ["-0.8*math.cos(q.anim_time*90*8-120)", 0, "3*math.sin(q.anim_time*90*4+70)"]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"0.5": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"1.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"1.5": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"2.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"2.5": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"3.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"3.5": "q.run_molang('cobblemon:stepsound_standard_large');"
|
||||
}
|
||||
},
|
||||
"animation.rhyhorn.ride_ground_walk": {
|
||||
@@ -1917,6 +1927,16 @@
|
||||
],
|
||||
"position": [0, "0.4+0.6*math.cos(q.anim_time*90*8-120)", 0]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"0.375": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"0.5": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"0.875": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"1.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"1.375": "q.run_molang('cobblemon:stepsound_standard_medium');",
|
||||
"1.5": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"1.875": "q.run_molang('cobblemon:stepsound_standard_medium');"
|
||||
}
|
||||
},
|
||||
"animation.rhyhorn.ride_ground_run": {
|
||||
|
||||
+12
@@ -329,6 +329,12 @@
|
||||
"locator_seat_1": {
|
||||
"rotation": [-15, 0, 0]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"1.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"2.0": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"3.0": "q.run_molang('cobblemon:stepsound_standard_large');"
|
||||
}
|
||||
},
|
||||
"animation.rhydon.ride_ground_walk": {
|
||||
@@ -807,6 +813,12 @@
|
||||
"locator_seat_1": {
|
||||
"rotation": [-15, 0, 0]
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.3333": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"0.8333": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"1.3333": "q.run_molang('cobblemon:stepsound_standard_large');",
|
||||
"1.8333": "q.run_molang('cobblemon:stepsound_standard_large');"
|
||||
}
|
||||
},
|
||||
"animation.rhydon.ride_ground_run": {
|
||||
|
||||
+4
@@ -391,6 +391,10 @@
|
||||
"1.0": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeline": {
|
||||
"0.0833": "q.run_molang('cobblemon:stepsound_minecraft');",
|
||||
"0.5833": "q.run_molang('cobblemon:stepsound_minecraft');"
|
||||
}
|
||||
},
|
||||
"animation.mr_mime.ground_run": {
|
||||
|
||||
@@ -2381,6 +2381,7 @@
|
||||
"cobblemon.command.spawnpokemon.nospecies": "Error: You need to include a Pokémon name or 'random'",
|
||||
"cobblemon.command.error.nonpc": "Error: You need to include a valid NPC identifier.",
|
||||
"cobblemon.command.held_item": "%1$s's %2$s was given the %3$s to hold.",
|
||||
"cobblemon.command.cosmetic_item": "%1$s's %2$s was given the %3$s to wear.",
|
||||
"cobblemon.command.giveallmarks": "%1$s's %2$s was given all available marks.",
|
||||
"cobblemon.command.givemark": "%1$s's %2$s was given a %3$s.",
|
||||
"cobblemon.command.givemark.already_has": "%1$s's %2$s already has a %3$s!",
|
||||
@@ -2434,6 +2435,8 @@
|
||||
"cobblemon.config.ui.max_pokemon_level.tooltip": "The maximum level Pokémon can get to.",
|
||||
"cobblemon.config.ui.max_pokemon_friendship": "Max Pokémon Friendship",
|
||||
"cobblemon.config.ui.max_pokemon_friendship.tooltip": "The maximum friendship value.",
|
||||
"cobblemon.config.ui.power_item_ride_stat_gain_interval_seconds": "Power Item Riding Stat Training Interval (Seconds)",
|
||||
"cobblemon.config.ui.power_item_ride_stat_gain_interval_seconds.tooltip": "Seconds between riding stat gains while riding a Pokémon holding a Power item. Defaults to 120 seconds. Set to -1 or 0 to disable; values below -1 are clamped to -1.",
|
||||
"cobblemon.config.ui.announce_drop_items": "Announce Drop Items",
|
||||
"cobblemon.config.ui.announce_drop_items.tooltip": "Whether to notify the Player of dropped items from defeating wild Pokémon.",
|
||||
"cobblemon.config.ui.default_drop_item_method": "Default Drop Item Method",
|
||||
|
||||
@@ -1653,6 +1653,18 @@
|
||||
"move.horndrill.target_2": {
|
||||
"sounds": [ { "name": "cobblemon:move/horndrill/horndrill_target_2", "volume": 1.0 } ]
|
||||
},
|
||||
"move.gigatonhammer.actor": {
|
||||
"sounds": [ { "name": "cobblemon:move/gigatonhammer/gigatonhammer_actor", "volume": 1.0 } ]
|
||||
},
|
||||
"move.gigatonhammer.target": {
|
||||
"sounds": [ { "name": "cobblemon:move/gigatonhammer/gigatonhammer_target", "volume": 1.0 } ]
|
||||
},
|
||||
"move.pyroball.actor": {
|
||||
"sounds": [ { "name": "cobblemon:move/pyroball/pyroball_actor", "volume": 1.0 } ]
|
||||
},
|
||||
"move.pyroball.target": {
|
||||
"sounds": [ { "name": "cobblemon:move/pyroball/pyroball_target", "volume": 1.0 } ]
|
||||
},
|
||||
"impact.normal": {
|
||||
"sounds": [
|
||||
{ "name": "cobblemon:move/impact_generic/impact_generic_fighting_1", "volume": 0.8 },
|
||||
@@ -8672,6 +8684,9 @@
|
||||
"pokemon.cinderace.cry": {
|
||||
"sounds": [ { "name": "cobblemon:pokemon/cinderace/cinderace_cry", "volume": 0.8 } ]
|
||||
},
|
||||
"pokemon.cinderace.pyroball": {
|
||||
"sounds": [ { "name": "cobblemon:pokemon/cinderace/cinderace_pyroball", "volume": 0.5 } ]
|
||||
},
|
||||
"pokemon.sobble.cry": {
|
||||
"sounds": [ { "name": "cobblemon:pokemon/sobble/sobble_cry", "volume": 0.8 } ]
|
||||
},
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
+35
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"timeline": [
|
||||
{
|
||||
"type": "add_holds",
|
||||
"holds": ["effects"]
|
||||
},
|
||||
{
|
||||
"type": "animation",
|
||||
"animation": ["gigatonhammer"],
|
||||
"delay": 0.3
|
||||
},
|
||||
{
|
||||
"type": "entity_molang",
|
||||
"entityCondition": "q.entity.is_user == true",
|
||||
"expressions": ["q.sound('move.gigatonhammer.actor');"]
|
||||
},
|
||||
{
|
||||
"type": "pause",
|
||||
"pause": 1.1
|
||||
},
|
||||
{
|
||||
"type": "entity_molang",
|
||||
"entityCondition": "q.entity.is_user == false && q.missed(q.entity.uuid) == false",
|
||||
"expressions": ["q.sound('move.gigatonhammer.target');"]
|
||||
},
|
||||
{
|
||||
"type": "remove_holds",
|
||||
"holds": ["effects"]
|
||||
},
|
||||
{
|
||||
"type": "pause",
|
||||
"pause": 1.5
|
||||
}
|
||||
]
|
||||
}
|
||||
+29
-2
@@ -3,11 +3,38 @@
|
||||
{
|
||||
"type": "add_holds",
|
||||
"holds": ["effects"]
|
||||
|
||||
},
|
||||
{
|
||||
"type": "animation",
|
||||
"animation": ["pyroball"],
|
||||
"delay": 2.05
|
||||
"animation": ["pyroball"]
|
||||
},
|
||||
{
|
||||
"type": "pause",
|
||||
"pause" : 0.1
|
||||
},
|
||||
{
|
||||
"type": "entity_molang",
|
||||
"entityCondition": "q.entity.is_user == true",
|
||||
"expressions": ["q.sound('move.pyroball.actor');"]
|
||||
},
|
||||
{
|
||||
"type": "entity_molang",
|
||||
"entityCondition": "q.entity.is_user == true",
|
||||
"expressions": ["q.sound('pokemon.cinderace.pyroball');"]
|
||||
},
|
||||
{
|
||||
"type": "pause",
|
||||
"pause" : 1.875
|
||||
},
|
||||
{
|
||||
"type": "entity_molang",
|
||||
"entityCondition": "q.entity.is_user == false && q.missed(q.entity.uuid) == false",
|
||||
"expressions": ["q.sound('move.pyroball.target');"]
|
||||
},
|
||||
{
|
||||
"type": "pause",
|
||||
"pause" : 0.175
|
||||
},
|
||||
{
|
||||
"type": "entity_particles",
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
}
|
||||
],
|
||||
"type": "cobblemon:cooking_pot_shapeless",
|
||||
"category": "medicines",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "create:experience_nugget"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"maleRatio": 0.875,
|
||||
"height": 16,
|
||||
"weight": 855,
|
||||
"silenceStepSounds": true,
|
||||
"pokedex": [
|
||||
"cobblemon.species.blastoise.desc"
|
||||
],
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"maleRatio": 0.5,
|
||||
"height": 17,
|
||||
"weight": 1200,
|
||||
"silenceStepSounds": true,
|
||||
"pokedex": [
|
||||
"cobblemon.species.dewgong.desc"
|
||||
],
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"maleRatio": 0.5,
|
||||
"height": 13,
|
||||
"weight": 545,
|
||||
"silenceStepSounds": true,
|
||||
"pokedex": [
|
||||
"cobblemon.species.mrmime.desc"
|
||||
],
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"maleRatio": 0.5,
|
||||
"height": 10,
|
||||
"weight": 295,
|
||||
"silenceStepSounds": true,
|
||||
"pokedex": [
|
||||
"cobblemon.species.parasect.desc"
|
||||
],
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"maleRatio": 0.5,
|
||||
"height": 19,
|
||||
"weight": 1200,
|
||||
"silenceStepSounds": true,
|
||||
"pokedex": [
|
||||
"cobblemon.species.rhydon.desc"
|
||||
],
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"maleRatio": 0.5,
|
||||
"height": 10,
|
||||
"weight": 1150,
|
||||
"silenceStepSounds": true,
|
||||
"pokedex": [
|
||||
"cobblemon.species.rhyhorn.desc"
|
||||
],
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"maleRatio": 0.875,
|
||||
"height": 20,
|
||||
"weight": 1000,
|
||||
"silenceStepSounds": true,
|
||||
"pokedex": [
|
||||
"cobblemon.species.venusaur.desc"
|
||||
],
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"cobblemon:tart_apple",
|
||||
"cobblemon:syrupy_apple",
|
||||
"cobblemon:candied_apple",
|
||||
{ "id": "create:honeyed_apple","required": false }
|
||||
{ "id": "create:honeyed_apple","required": false },
|
||||
{ "id": "nomansland:honeyed_apple","required": false }
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user