Merge branch 'ponigiri' into 'main'

Adds Ponigiri, Poke Puffs, Sinister Tea, and berry data changes and tool tip changes

See merge request cable-mc/cobblemon!1658
This commit is contained in:
Nick
2025-05-12 15:22:58 -07:00
392 changed files with 4360 additions and 241 deletions
+2
View File
@@ -22,6 +22,7 @@
- Added `translucent_cull` boolean option into resolver's layer to allow for translucent textures with culling
- Added [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) support for items held by Pokémon.
- Added modification to Minecraft Creative Inventory search to account for item names that contain `poké` when input contains `poke`.
- Added Campfire Pot as well as loads of new food items (Poke Puffs, Ponigiri, Sinister Tea, etc)
### Pokémon Added
@@ -138,6 +139,7 @@
- Renamed `pokemonId` and `type` to `species` in relevant Advancement triggers for conformity, this is a breaking change.
- Added a separate `species` argument to the `pick_starter`, `pasture_use` and `resurrect_pokemon` Advancement triggers.
- Made `CobblemonAgingDespawner` thresholds configurable via the config file.
- Tweaked Berry flavor data to balance cooking pot mechanics
### Fixes
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
@@ -9,12 +9,7 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.PotComponent
import com.cobblemon.mod.common.item.components.BaitEffectsComponent
import com.cobblemon.mod.common.item.components.FlavourComponent
import com.cobblemon.mod.common.item.components.FoodColourComponent
import com.cobblemon.mod.common.item.components.HeldItemCapableComponent
import com.cobblemon.mod.common.item.components.PokemonItemComponent
import com.cobblemon.mod.common.item.components.RodBaitComponent
import com.cobblemon.mod.common.item.components.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
import net.minecraft.core.component.DataComponentType
@@ -60,6 +55,20 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
.build())
val INGREDIENT: DataComponentType<IngredientComponent> = create("ingredient", DataComponentType.builder<IngredientComponent>()
.persistent(IngredientComponent.CODEC)
.networkSynchronized(IngredientComponent.PACKET_CODEC)
.build())
val FOOD: DataComponentType<FoodComponent> = create("food", DataComponentType.builder<FoodComponent>()
.persistent(FoodComponent.CODEC)
.networkSynchronized(FoodComponent.PACKET_CODEC)
.build())
val MOB_EFFECTS: DataComponentType<MobEffectsComponent> = create("mob_effects", DataComponentType.builder<MobEffectsComponent>()
.persistent(MobEffectsComponent.CODEC)
.networkSynchronized(MobEffectsComponent.PACKET_CODEC)
.build())
fun register() {
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:pokemon_item"), POKEMON_ITEM)
@@ -68,6 +77,9 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait_effects"), BAIT_EFFECTS)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:flavour"), FLAVOUR)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food_colour"), FOOD_COLOUR)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ingredient"), INGREDIENT)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:mob_effects"), MOB_EFFECTS)
}
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
@@ -34,6 +34,8 @@ import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.food.PonigiriItem
import com.cobblemon.mod.common.item.food.SinisterTeaItem
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
import com.cobblemon.mod.common.platform.PlatformRegistry
@@ -363,123 +365,97 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val APRIJUICE_PINK = aprijuiceItem(Apricorn.PINK)
@JvmField
val POKE_PUFF = noSettingsItem("poke_puff") // todo make a PokePuffItem class for friendship boosting purposes
val PONIGIRI = create("ponigiri", PonigiriItem())
@JvmField
val SINISTER_TEA = create("sinister_tea", SinisterTeaItem())
@JvmField
val POKE_PUFF = pokepuffItem("poke_puff") // todo make a PokePuffItem class for friendship boosting purposes
// FOODS
@JvmField
val SWEET_HEART = noSettingsItem("sweet_heart") // todo make a SweetHeartItem class for breeding purposes
@JvmField
val TASTY_TAIL = create("tasty_tail", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(8)
.saturationModifier(12.8F)
.alwaysEdible()
.build())) {})
@JvmField
val PEWTER_CRUNCHIES = create("pewter_crunchies", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val RAGE_CANDY_BAR = create("rage_candy_bar", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val LAVA_COOKIE = create("lava_cookie", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val OLD_GATEAU = create("old_gateau", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val CASTELIACONE = create("casteliacone", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val SHALOR_SABLE = create("shalor_sable", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
val SHALOUR_SABLE = create("shalour_sable", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val LUMIOSE_GALETTE = create("lumiose_galette", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val BIG_MALASADA = create("big_malasada", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
/*@JvmField // todo see what we are doing for these (are there different kinds?)
val CURRY = create("curry", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
@@ -499,16 +475,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val JUBILIFE_MUFFIN = create("jubilife_muffin", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
/*@JvmField // todo see what we are doing for these (are there different kinds?)
val SANDWICH = create("sandwich", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
@@ -536,70 +507,31 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val POTATO_MOCHI = create("potato_mochi", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val FRIED_RICE = create("fried_rice", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val CANDIED_APPLE = create("candied_apple", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
@JvmField
val CANDIED_BERRY = create("candied_berry", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.nutrition(10) // todo get final values for this from vera
.saturationModifier(1.2F) // todo get final values for this from vera
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val JELLY_DOUGHNUT = create("jelly_doughnut", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
.build())) {})
// todo etc?
@@ -1642,6 +1574,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
return item
}
private fun pokepuffItem(name: String): PokePuffItem {
val item = create("poke_puff", PokePuffItem())
return item
}
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
name,
CobblemonItem(Item.Properties()).also {
@@ -23,7 +23,8 @@ enum class Flavour(val colour: Int, val chatFormatting: ChatFormatting): StringR
DRY(0xFF0000, ChatFormatting.DARK_AQUA),
SWEET(0x0000FF, ChatFormatting.LIGHT_PURPLE),
BITTER(0xFFFF00, ChatFormatting.GREEN),
SOUR(0xFF00FF, ChatFormatting.YELLOW);
SOUR(0xFF00FF, ChatFormatting.YELLOW),
MILD(0xFF00FF, ChatFormatting.DARK_PURPLE);
override fun getSerializedName() = name
companion object {
@@ -54,6 +54,25 @@ fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolea
acc
}
return FastColor.ARGB32.color(
alphaSum / colors.size,
redSum / colors.size,
greenSum / colors.size,
blueSum / colors.size
)
}
fun getColourMixFromColors(colors: List<Int>): Int? {
if (colors.isEmpty()) return null
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
acc[0] += FastColor.ARGB32.alpha(color)
acc[1] += FastColor.ARGB32.red(color)
acc[2] += FastColor.ARGB32.green(color)
acc[3] += FastColor.ARGB32.blue(color)
acc
}
return FastColor.ARGB32.color(
alphaSum / colors.size,
redSum / colors.size,
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cooking
import com.cobblemon.mod.common.item.components.FoodComponent
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
data class Food(
val hunger: Int = 0,
val saturation: Float = 0f,
) {
companion object {
val CODEC: Codec<Food> = RecordCodecBuilder.create { builder ->
builder.group(
Codec.INT.optionalFieldOf("hunger", 0).forGetter { it.hunger },
Codec.FLOAT.optionalFieldOf("saturation", 0f).forGetter { it.saturation },
).apply(builder, ::Food)
}
}
fun toComponent(): FoodComponent = FoodComponent(hunger, saturation)
}
@@ -0,0 +1,38 @@
/*
* 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.cooking
import com.cobblemon.mod.common.item.components.FoodComponent
import kotlin.math.ceil
import kotlin.math.round
object FoodUtils {
fun merge(components: List<FoodComponent>, extraHunger: Int = 0, extraSaturation: Float = 0f): FoodComponent {
if (components.isEmpty()) return FoodComponent(0, 0f)
val count = components.size
val totalHunger = components.sumOf { it.hunger.toDouble() } + extraHunger
val totalSaturation = components.sumOf { it.saturation.toDouble() } + extraSaturation
val multiplier = when (count) {
1 -> 1.0
2 -> 0.8
3 -> 0.6
else -> 0.4
}
val adjustedHunger = ceil(totalHunger * multiplier)
val adjustedSaturation = totalSaturation * multiplier
return FoodComponent(
hunger = adjustedHunger.toInt(),
saturation = (round(adjustedSaturation * 100) / 100f).toFloat()
)
}
}
@@ -0,0 +1,24 @@
/*
* 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.cooking
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
data class MobCookingEffects(
val appliedEffects: List<SerializableMobEffectInstance> = emptyList()
) {
companion object {
val CODEC: Codec<MobCookingEffects> = RecordCodecBuilder.create { builder ->
builder.group(
SerializableMobEffectInstance.CODEC.listOf().optionalFieldOf("appliedEffects", emptyList()).forGetter { it.appliedEffects }
).apply(builder, ::MobCookingEffects)
}
}
}
@@ -0,0 +1,72 @@
/*
* 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.cooking
import net.minecraft.world.effect.MobEffectInstance
import kotlin.math.ceil
import kotlin.math.max
object MobEffectUtils {
fun mergeEffects(effects: List<SerializableMobEffectInstance>): List<SerializableMobEffectInstance> {
val grouped = effects.groupBy { it.effect }
return grouped.map { (effectId, group) ->
val amplifier = mergeAmplifiers(group.map { it.amplifier })
val duration = mergeDurations(group.map { it.duration })
val first = group.first()
SerializableMobEffectInstance(
effect = effectId,
duration = duration,
amplifier = amplifier,
ambient = first.ambient,
visible = first.visible,
showIcon = first.showIcon
)
}
}
private fun mergeDurations(durations: List<Int>): Int {
if (durations.isEmpty()) return 0
val sorted = durations.sortedDescending()
var result = 0.0
for ((index, value) in sorted.withIndex()) {
val multiplier = when (index) {
0 -> 1.0
1 -> 0.75
2 -> 0.5
else -> 0.25
}
result += value * multiplier
}
return ceil(result).toInt()
}
private fun mergeAmplifiers(amplifiers: List<Int>): Int {
if (amplifiers.isEmpty()) return 0
val sorted = amplifiers.sortedDescending()
var result = 0.0
for ((index, value) in sorted.withIndex()) {
val multiplier = when (index) {
0 -> 1.0
1 -> 0.75
2 -> 0.5
else -> 0.25
}
result += (value + 1) * multiplier
}
return ceil(result).toInt() - 1
}
}
@@ -0,0 +1,95 @@
/*
* 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.cooking
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.item.PokePuffItem
import com.cobblemon.mod.common.item.PokePuffItem.Companion.DISLIKED_FLAVOR_MULTIPLIER
import com.cobblemon.mod.common.item.PokePuffItem.Companion.LIKED_FLAVOR_MULTIPLIER
import com.cobblemon.mod.common.pokemon.Nature
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.ItemStack
import net.minecraft.core.registries.BuiltInRegistries
object PokePuffUtils {
fun calculateFriendshipChange(stack: ItemStack, nature: Nature): Int {
val dominantFlavour = getDominantFlavour(stack) ?: return 0
val isNeutralNature = nature.favouriteFlavour == nature.dislikedFlavour
val (baseFriendship) = calculateBaseFriendship(stack)
return when {
dominantFlavour == nature.favouriteFlavour -> (baseFriendship / LIKED_FLAVOR_MULTIPLIER).toInt()
dominantFlavour == Flavour.MILD && isNeutralNature -> (baseFriendship / 2.0).coerceAtLeast(1.0).toInt()
else -> (-baseFriendship / DISLIKED_FLAVOR_MULTIPLIER).toInt()
}
}
fun calculateBaseFriendship(stack: ItemStack): Pair<Double, Double> {
val ingredientIds = stack.get(CobblemonItemComponents.INGREDIENT)?.ingredientIds ?: emptyList()
var baseFriendship = 0.0
for (id in ingredientIds) {
val item = BuiltInRegistries.ITEM.get(id)
val itemStack = ItemStack(item)
val seasoning = Seasonings.getFromItemStack(itemStack) ?: continue
val dominantValue = seasoning.flavours?.values?.maxOrNull() ?: 0
baseFriendship += dominantValue
}
val ingredientStrings = ingredientIds.map { it.toString() }
val hasSugar = "minecraft:sugar" in ingredientStrings
val hasSweet = ingredientStrings.any { it.startsWith("cobblemon:") && it.endsWith("_sweet") }
val multiplier = when {
hasSugar && hasSweet -> 5.0
hasSweet -> 2.25
hasSugar -> 1.75
else -> 1.0
}
val finalBaseFriendship = baseFriendship * multiplier
return finalBaseFriendship to multiplier
}
fun getDominantFlavour(stack: ItemStack): Flavour? {
val flavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: return null
val max = flavours.values.maxOrNull() ?: return null
val dominant = flavours.filterValues { it == max }.keys
return when {
dominant.isEmpty() -> null
dominant.size > 1 -> Flavour.MILD
else -> dominant.first()
}
}
fun getFlavorNatureLabel(flavour: Flavour): String {
return when (flavour) {
Flavour.SPICY -> "attack"
Flavour.DRY -> "special_attack"
Flavour.SWEET -> "speed"
Flavour.BITTER -> "special_defense"
Flavour.SOUR -> "defense"
Flavour.MILD -> "neutral"
}
}
fun getFriendshipChangeLiked(stack: ItemStack): Int {
val (baseFriendship) = calculateBaseFriendship(stack)
return (baseFriendship / LIKED_FLAVOR_MULTIPLIER).toInt()
}
fun getFriendshipChangeDisliked(stack: ItemStack): Int {
val (baseFriendship) = calculateBaseFriendship(stack)
return (baseFriendship / DISLIKED_FLAVOR_MULTIPLIER).toInt()
}
}
@@ -25,11 +25,15 @@ import net.minecraft.world.item.Item
data class Seasoning(
val ingredient: RegistryLikeCondition<Item>,
@SerializedName("flavours", alternate = ["flavors"])
val flavours: Map<Flavour, Int>,
val flavours: Map<Flavour, Int>? = null,
@SerializedName("colour", alternate = ["color"])
val colour: DyeColor,
@SerializedName("baitEffects")
val baitEffects: List<SpawnBait.Effect> = emptyList()
val baitEffects: List<SpawnBait.Effect> = emptyList(),
@SerializedName("food")
val food: Food? = null,
@SerializedName("mobEffects")
val mobEffects: MobCookingEffects? = null
) {
companion object {
val CODEC: Codec<Seasoning> = RecordCodecBuilder.create { builder ->
@@ -37,7 +41,9 @@ data class Seasoning(
ITEM_REGISTRY_LIKE_CODEC.fieldOf("ingredient").forGetter { it.ingredient },
Codec.unboundedMap(Flavour.CODEC, Codec.INT).fieldOf("flavours").forGetter { it.flavours }, // Use map codec
DyeColor.CODEC.fieldOf("colour").forGetter { it.colour },
SpawnBait.Effect.CODEC.listOf().optionalFieldOf("baitEffects", emptyList()).forGetter { it.baitEffects }
SpawnBait.Effect.CODEC.listOf().optionalFieldOf("baitEffects", emptyList()).forGetter { it.baitEffects },
Food.CODEC.fieldOf("food").forGetter { it.food },
MobCookingEffects.CODEC.fieldOf("mobEffects").forGetter { it.mobEffects }
).apply(builder, ::Seasoning)
}
@@ -47,7 +53,9 @@ data class Seasoning(
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
flavours = Flavour.entries.associate { it to 0 },
colour = DyeColor.WHITE,
baitEffects = emptyList()
baitEffects = emptyList(),
food = Food(),
mobEffects = MobCookingEffects()
)
}
}
@@ -46,7 +46,9 @@ object Seasonings : JsonDataRegistry<Seasoning> {
val BLANK_SEASONING = Seasoning(
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
flavours = emptyMap(),
colour = DyeColor.WHITE
colour = DyeColor.WHITE,
food = Food(),
mobEffects = MobCookingEffects()
)
override fun sync(player: ServerPlayer) {
@@ -59,7 +61,10 @@ object Seasonings : JsonDataRegistry<Seasoning> {
it.identifier to Seasoning(
ingredient = RegistryLikeIdentifierCondition(it.identifier),
flavours = it.flavours.toMap(),
colour = it.colour
colour = it.colour,
baitEffects = emptyList(),
food = Food(),
mobEffects = MobCookingEffects()
)
}.toMutableMap()
finalData.putAll(data)
@@ -75,8 +80,29 @@ object Seasonings : JsonDataRegistry<Seasoning> {
val holder = stack.itemHolder
val seasoning = seasonings.find { it.ingredient.fits(holder) } ?: BLANK_SEASONING
val inherentFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: emptyMap()
val seasoningFlavours = seasoning.flavours ?: emptyMap()
return seasoning.flavours.mapValues { (flavour, value) -> inherentFlavours.getOrDefault(flavour, 0) + value }
return seasoningFlavours.mapValues { (flavour, value) ->
inherentFlavours.getOrDefault(flavour, 0) + value
}
}
fun getFoodFromItemStack(stack: ItemStack): Food? {
return getFromItemStack(stack)?.food
}
fun hasFood(stack: ItemStack): Boolean {
val effects = getFromItemStack(stack)?.food ?: return false
return effects.hunger > 0 || effects.saturation > 0f
}
fun getMobEffectFromItemStack(stack: ItemStack): MobCookingEffects? {
return getFromItemStack(stack)?.mobEffects
}
fun hasMobEffect(stack: ItemStack): Boolean {
val effects = getFromItemStack(stack)?.mobEffects ?: return false
return effects.appliedEffects.isNotEmpty()
}
fun getBaitEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
@@ -0,0 +1,45 @@
/*
* 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.cooking
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.Holder
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectInstance
data class SerializableMobEffectInstance(
val effect: ResourceLocation,
val duration: Int,
val amplifier: Int = 0,
val ambient: Boolean = false,
val visible: Boolean = true,
val showIcon: Boolean = true
) {
fun toInstance(): MobEffectInstance {
val holder = BuiltInRegistries.MOB_EFFECT.getHolder(effect)
.orElseThrow { IllegalArgumentException("Unknown MobEffect: $effect") }
return MobEffectInstance(holder, duration, amplifier, ambient, visible, showIcon)
}
companion object {
val CODEC: Codec<SerializableMobEffectInstance> = RecordCodecBuilder.create { builder ->
builder.group(
ResourceLocation.CODEC.fieldOf("effect").forGetter { it.effect },
Codec.INT.fieldOf("duration").forGetter { it.duration },
Codec.INT.fieldOf("amplifier").forGetter { it.amplifier },
Codec.BOOL.optionalFieldOf("ambient", false).forGetter { it.ambient },
Codec.BOOL.optionalFieldOf("visible", true).forGetter { it.visible },
Codec.BOOL.optionalFieldOf("showIcon", true).forGetter { it.showIcon }
).apply(builder, ::SerializableMobEffectInstance)
}
}
}
@@ -8,6 +8,8 @@
package com.cobblemon.mod.common.api.fishing
import kotlin.math.ceil
object SpawnBaitUtils {
fun mergeEffects(effects: List<SpawnBait.Effect>): List<SpawnBait.Effect> {
val grouped = effects.groupBy { Pair(it.type, it.subcategory) }
@@ -25,12 +27,12 @@ object SpawnBaitUtils {
val multiplier = when (count) {
2 -> 0.8
3 -> 0.9
3 -> 0.6
else -> 1.0
}
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
val adjustedValue = totalValue * multiplier
val adjustedValue = ceil(totalValue * multiplier)
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
}
@@ -32,6 +32,8 @@ import com.cobblemon.mod.common.client.render.block.*
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.color.AprijuiceItemColorProvider
import com.cobblemon.mod.common.client.render.color.PokeBaitItemColorProvider
import com.cobblemon.mod.common.client.render.color.PonigiriItemColorProvider
import com.cobblemon.mod.common.client.render.color.SinisterTeaItemColorProvider
import com.cobblemon.mod.common.client.render.entity.PokeBobberEntityRenderer
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
@@ -51,6 +53,7 @@ import com.cobblemon.mod.common.client.trade.ClientTrade
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.item.food.SinisterTeaItem
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext
import com.cobblemon.mod.common.util.isLookingAt
@@ -171,6 +174,9 @@ object CobblemonClient {
TooltipManager.registerTooltipGenerator(FishingRodTooltipGenerator)
TooltipManager.registerTooltipGenerator(SeasoningTooltipGenerator)
TooltipManager.registerTooltipGenerator(AprijuiceTooltipGenerator)
TooltipManager.registerTooltipGenerator(PokePuffTooltipGenerator)
TooltipManager.registerTooltipGenerator(FoodTooltipGenerator)
TooltipManager.registerTooltipGenerator(MobEffectTooltipGenerator)
}
fun registerFlywheelRenderers() {
@@ -341,6 +347,8 @@ object CobblemonClient {
implementation.registerItemColors(PokeBaitItemColorProvider, CobblemonItems.POKE_BAIT)
implementation.registerItemColors(PokeBaitItemColorProvider, CobblemonItems.LURE_CAKE)
implementation.registerItemColors(PokeBaitItemColorProvider, CobblemonItems.POKE_CAKE)
implementation.registerItemColors(PonigiriItemColorProvider, CobblemonItems.PONIGIRI)
implementation.registerItemColors(SinisterTeaItemColorProvider, CobblemonItems.SINISTER_TEA)
}
fun reloadCodedAssets(resourceManager: ResourceManager) {
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.color
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.cooking.getColourMixFromColors
import com.cobblemon.mod.common.api.cooking.getColourMixFromFlavours
import com.cobblemon.mod.common.client.pot.CookingQuality
import net.minecraft.ChatFormatting
import net.minecraft.client.color.item.ItemColor
import net.minecraft.util.FastColor
import net.minecraft.world.item.ItemStack
object PonigiriItemColorProvider : ItemColor {
private const val PONIGIRI_INDEX = 0
override fun getColor(stack: ItemStack, layer: Int): Int {
if (layer == 1 || layer == 2) return -1
val colorComponent = stack.get(CobblemonItemComponents.FOOD_COLOUR) ?: return -1
if (layer == PONIGIRI_INDEX) {
val colorMix = getColourMixFromColors(colorComponent.getColoursAsARGB())
if (colorMix != null) return colorMix
}
return -1
}
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.color
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.cooking.getColourMixFromColors
import com.cobblemon.mod.common.api.cooking.getColourMixFromFlavours
import com.cobblemon.mod.common.client.pot.CookingQuality
import net.minecraft.ChatFormatting
import net.minecraft.client.color.item.ItemColor
import net.minecraft.util.FastColor
import net.minecraft.world.item.ItemStack
object SinisterTeaItemColorProvider : ItemColor {
private const val TEA_INDEX = 1
override fun getColor(stack: ItemStack, layer: Int): Int {
if (layer == 0 || layer == 2) return -1
val colorComponent = stack.get(CobblemonItemComponents.FOOD_COLOUR) ?: return -1
if (layer == TEA_INDEX) {
val colorMix = getColourMixFromColors(colorComponent.getColoursAsARGB())
if (colorMix != null) return colorMix
}
return -1
}
}
@@ -10,10 +10,12 @@ package com.cobblemon.mod.common.client.render.item
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.client.pot.CookingQuality
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.item.interactive.PokerodItem
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.ChatFormatting
import net.minecraft.client.renderer.item.ItemProperties
import net.minecraft.resources.ResourceLocation
@@ -94,6 +96,41 @@ object CobblemonModelPredicateRegistry {
}
}
ItemProperties.register(
CobblemonItems.PONIGIRI,
cobblemonResource("ponigiri_overlay")
) { stack, world, entity, seed ->
val component = stack.get(CobblemonItemComponents.INGREDIENT)
val id = component?.ingredientIds?.firstOrNull()?.toString() ?: return@register 0.0f
return@register when (id) {
"minecraft:potato" -> 0.01f
"minecraft:beetroot" -> 0.02f
"minecraft:carrot" -> 0.03f
"minecraft:dried_kelp" -> 0.04f
"cobblemon:medicinal_leek" -> 0.05f
"minecraft:red_mushroom" -> 0.06f
"minecraft:brown_mushroom" -> 0.07f
"minecraft:pumpkin" -> 0.08f
"cobblemon:rice" -> 0.09f
"minecraft:raw_chicken" -> 0.10f
"minecraft:raw_cod" -> 0.11f
"minecraft:raw_mutton" -> 0.12f
"minecraft:raw_porkchop" -> 0.13f
"minecraft:raw_rabbit" -> 0.14f
"minecraft:raw_salmon" -> 0.15f
"minecraft:raw_beef" -> 0.16f
"minecraft:egg" -> 0.17f
"minecraft:poisonous_potato" -> 0.18f
"minecraft:rotten_flesh" -> 0.19f
"minecraft:golden_carrot" -> 0.20f
"cobblemon:vivichoke" -> 0.21f
"cobblemon:tasty_tail" -> 0.22f
"minecraft:sweet_berries" -> 0.23f
else -> 0.0f
}
}
val aprijuice = listOf(
CobblemonItems.APRIJUICE_BLACK,
CobblemonItems.APRIJUICE_GREEN,
@@ -117,6 +154,34 @@ object CobblemonModelPredicateRegistry {
}
}
ItemProperties.register(CobblemonItems.POKE_PUFF, cobblemonResource("poke_puff_combined")) { stack, _, _, _ ->
val dominantFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.getDominantFlavours()
val flavour = when {
dominantFlavours == null || dominantFlavours.isEmpty() -> "plain"
dominantFlavours.size > 1 -> "mild"
else -> dominantFlavours.first().name.lowercase()
}
val ingredients =
stack.get(CobblemonItemComponents.INGREDIENT)?.ingredientIds?.map { it.toString() } ?: emptyList()
val hasSugar = "minecraft:sugar" in ingredients
// todo CRAB NOTE: we may want a map or item tag instead
val sweet = ingredients.firstOrNull {
it.startsWith("cobblemon:") && it.endsWith("_sweet")
}?.removePrefix("cobblemon:")?.removeSuffix("_sweet")
val key = when {
hasSugar && sweet != null -> "overlay_${flavour}_${sweet}"
sweet != null && flavour != null -> "overlay_${sweet}_${flavour}"
sweet != null -> "overlay_${sweet}"
hasSugar && flavour != null -> "overlay_${flavour}"
flavour != null -> "overlay_${flavour}_only"
else -> "overlay_plain_only"
}
return@register PokePuffItemModelRegistry.getModelId(key)
}
}
}
@@ -0,0 +1,145 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.item
object PokePuffItemModelRegistry {
private val modelMap = mapOf(
"overlay_spicy" to 0.001f,
"overlay_spicy_only" to 0.002f,
"overlay_spicy_strawberry" to 0.003f,
"overlay_dry_only" to 0.004f,
"overlay_spicy_love" to 0.005f,
"overlay_sweet_only" to 0.006f,
"overlay_spicy_berry" to 0.007f,
"overlay_bitter_only" to 0.008f,
"overlay_spicy_ribbon" to 0.009f,
"overlay_sour_only" to 0.010f,
"overlay_spicy_clover" to 0.011f,
"overlay_mild_only" to 0.012f,
"overlay_spicy_flower" to 0.013f,
"overlay_plain_only" to 0.014f,
"overlay_spicy_star" to 0.015f,
"overlay_dry" to 0.016f,
"overlay_dry_strawberry" to 0.017f,
"overlay_dry_love" to 0.018f,
"overlay_dry_berry" to 0.019f,
"overlay_dry_ribbon" to 0.020f,
"overlay_dry_clover" to 0.021f,
"overlay_dry_flower" to 0.022f,
"overlay_dry_star" to 0.023f,
"overlay_sweet" to 0.024f,
"overlay_sweet_strawberry" to 0.025f,
"overlay_sweet_love" to 0.026f,
"overlay_sweet_berry" to 0.027f,
"overlay_sweet_ribbon" to 0.028f,
"overlay_sweet_clover" to 0.029f,
"overlay_sweet_flower" to 0.030f,
"overlay_sweet_star" to 0.031f,
"overlay_bitter" to 0.032f,
"overlay_bitter_strawberry" to 0.033f,
"overlay_bitter_love" to 0.034f,
"overlay_bitter_berry" to 0.035f,
"overlay_bitter_ribbon" to 0.036f,
"overlay_bitter_clover" to 0.037f,
"overlay_bitter_flower" to 0.038f,
"overlay_bitter_star" to 0.039f,
"overlay_sour" to 0.040f,
"overlay_sour_strawberry" to 0.041f,
"overlay_sour_love" to 0.042f,
"overlay_sour_berry" to 0.043f,
"overlay_sour_ribbon" to 0.044f,
"overlay_sour_clover" to 0.045f,
"overlay_sour_flower" to 0.046f,
"overlay_sour_star" to 0.047f,
"overlay_mild" to 0.048f,
"overlay_mild_strawberry" to 0.049f,
"overlay_mild_love" to 0.050f,
"overlay_mild_berry" to 0.051f,
"overlay_mild_ribbon" to 0.052f,
"overlay_clover" to 0.053f,
"overlay_mild_clover" to 0.054f,
"overlay_flower" to 0.055f,
"overlay_mild_flower" to 0.056f,
"overlay_star" to 0.057f,
"overlay_mild_star" to 0.058f,
"overlay_plain" to 0.059f,
"overlay_strawberry" to 0.060f,
"overlay_plain_strawberry" to 0.061f,
"overlay_love" to 0.062f,
"overlay_plain_love" to 0.063f,
"overlay_berry" to 0.064f,
"overlay_plain_berry" to 0.065f,
"overlay_ribbon" to 0.066f,
"overlay_plain_ribbon" to 0.067f,
"overlay_strawberry_spicy" to 0.068f,
"overlay_strawberry_dry" to 0.069f,
"overlay_strawberry_sweet" to 0.070f,
"overlay_strawberry_bitter" to 0.071f,
"overlay_strawberry_sour" to 0.072f,
"overlay_strawberry_mild" to 0.073f,
"overlay_strawberry_plain" to 0.074f,
"overlay_love_spicy" to 0.075f,
"overlay_love_dry" to 0.076f,
"overlay_love_sweet" to 0.077f,
"overlay_love_bitter" to 0.078f,
"overlay_love_sour" to 0.079f,
"overlay_love_mild" to 0.080f,
"overlay_love_plain" to 0.081f,
"overlay_berry_spicy" to 0.082f,
"overlay_berry_dry" to 0.083f,
"overlay_berry_sweet" to 0.084f,
"overlay_berry_bitter" to 0.085f,
"overlay_berry_sour" to 0.086f,
"overlay_berry_mild" to 0.087f,
"overlay_berry_plain" to 0.088f,
"overlay_ribbon_spicy" to 0.089f,
"overlay_ribbon_dry" to 0.090f,
"overlay_ribbon_sweet" to 0.091f,
"overlay_ribbon_bitter" to 0.092f,
"overlay_ribbon_sour" to 0.093f,
"overlay_ribbon_mild" to 0.094f,
"overlay_ribbon_plain" to 0.095f,
"overlay_clover_spicy" to 0.096f,
"overlay_clover_dry" to 0.097f,
"overlay_clover_sweet" to 0.098f,
"overlay_clover_bitter" to 0.099f,
"overlay_clover_sour" to 0.100f,
"overlay_clover_mild" to 0.101f,
"overlay_clover_plain" to 0.102f,
"overlay_flower_spicy" to 0.103f,
"overlay_flower_dry" to 0.104f,
"overlay_flower_sweet" to 0.105f,
"overlay_flower_bitter" to 0.106f,
"overlay_flower_sour" to 0.107f,
"overlay_flower_mild" to 0.108f,
"overlay_flower_plain" to 0.109f,
"overlay_star_spicy" to 0.110f,
"overlay_star_dry" to 0.111f,
"overlay_star_sweet" to 0.112f,
"overlay_star_bitter" to 0.113f,
"overlay_star_sour" to 0.114f,
"overlay_star_mild" to 0.115f,
"overlay_star_plain" to 0.116f,
"overlay_plain_clover" to 0.117f,
"overlay_plain_flower" to 0.118f,
"overlay_plain_star" to 0.119f
)
fun getModelId(key: String): Float {
return modelMap[key] ?: 0.0f
}
}
@@ -0,0 +1,35 @@
/*
* 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.tooltips
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.text.blue
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.text.yellow
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
object FoodTooltipGenerator : TooltipGenerator() {
private val foodHeader by lazy { lang("item_class.food").blue() }
override fun generateCategoryTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
val food = stack.get(CobblemonItemComponents.FOOD) ?: return null
return mutableListOf(foodHeader)
}
override fun generateAdditionalTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
val food = stack.get(CobblemonItemComponents.FOOD) ?: return null
return mutableListOf(
lang("tooltip.food.hunger", Component.literal("${food.hunger}").yellow()),
lang("tooltip.food.saturation", Component.literal("%.2f".format(food.saturation)).green())
)
}
}
@@ -0,0 +1,89 @@
/*
* 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.tooltips
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.text.blue
import com.cobblemon.mod.common.api.text.green
import com.cobblemon.mod.common.api.text.yellow
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.Minecraft
import net.minecraft.network.chat.Component
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.item.ItemStack
import net.minecraft.world.effect.MobEffectUtil
object MobEffectTooltipGenerator : TooltipGenerator() {
private val effectHeader by lazy { lang("item_class.mob_effect").blue() }
override fun generateCategoryTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
val effects = stack.get(CobblemonItemComponents.MOB_EFFECTS)?.mobEffects ?: return null
return if (effects.isNotEmpty()) mutableListOf(effectHeader) else null
}
override fun generateAdditionalTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
val effects = stack.get(CobblemonItemComponents.MOB_EFFECTS)?.mobEffects ?: return null
if (effects.isEmpty()) return null
val tickRate = Minecraft.getInstance().level?.tickRateManager()?.tickrate() ?: 20.0f
val result = mutableListOf<Component>()
// Always add the header FIRST, even for additional tooltip
result.add(effectHeader)
for (instance in effects) {
val name = instance.effect.value().descriptionId
val duration = MobEffectUtil.formatDuration(instance, 1.0f, tickRate) // Already a Component
val amplifierRoman = getRomanNumeral(instance.amplifier + 1)
result.add(
lang(
"tooltip.mob_effect_entry",
Component.translatable(name).yellow(),
Component.literal(amplifierRoman).green(),
duration.string.green()
)
)
}
return result
}
private fun getRomanNumeral(number: Int): String {
if (number <= 0) return number.toString() // no Roman numeral for zero or negatives
val numerals = listOf(
1000 to "M",
900 to "CM",
500 to "D",
400 to "CD",
100 to "C",
90 to "XC",
50 to "L",
40 to "XL",
10 to "X",
9 to "IX",
5 to "V",
4 to "IV",
1 to "I"
)
var remaining = number
val result = StringBuilder()
for ((value, numeral) in numerals) {
while (remaining >= value) {
result.append(numeral)
remaining -= value
}
}
return result.toString()
}
}
@@ -0,0 +1,68 @@
/*
* 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.tooltips
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.api.cooking.PokePuffUtils
import com.cobblemon.mod.common.api.text.blue
import com.cobblemon.mod.common.item.PokePuffItem
import com.cobblemon.mod.common.util.lang
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
object PokePuffTooltipGenerator : TooltipGenerator() {
override fun generateCategoryTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
if (stack.item !is PokePuffItem) return null
if (stack.get(CobblemonItemComponents.FLAVOUR) == null) return null
return mutableListOf(lang("tooltip.poke_puff.friendship_effects").blue())
}
override fun generateAdditionalTooltip(stack: ItemStack, lines: MutableList<Component>): MutableList<Component>? {
if (stack.item !is PokePuffItem) return null
// val flavourComponent = stack.get(CobblemonItemComponents.FLAVOUR) ?: return null
val resultLines = mutableListOf<Component>()
// resultLines.addAll(generateAdditionalFlavorTooltip(flavourComponent.flavours))
val dominantFlavour = PokePuffUtils.getDominantFlavour(stack)
if (dominantFlavour != null) {
val friendshipLiked = PokePuffUtils.getFriendshipChangeLiked(stack)
val friendshipDisliked = PokePuffUtils.getFriendshipChangeDisliked(stack)
// Get the nature label
val natureLabelKey = when (dominantFlavour) {
Flavour.MILD -> "tooltip.cobblemon.poke_puff.nature.neutral"
else -> "cobblemon.stat.${PokePuffUtils.getFlavorNatureLabel(dominantFlavour)}.name"
}
resultLines.add(Component.literal(""))
resultLines.add(lang("tooltip.poke_puff.friendship_effects").blue())
resultLines.add(
Component.translatable(
"tooltip.cobblemon.poke_puff.friendship_increase",
friendshipLiked.toString(),
Component.translatable(natureLabelKey)
).withStyle(ChatFormatting.GREEN)
)
resultLines.add(
Component.translatable(
"tooltip.cobblemon.poke_puff.friendship_decrease",
friendshipDisliked.toString()
).withStyle(ChatFormatting.RED)
)
}
return resultLines
}
}
@@ -22,10 +22,14 @@ import net.minecraft.network.chat.Component
import net.minecraft.network.chat.Component.translatable
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResultHolder
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.UseAnim
import net.minecraft.world.level.Level
class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)), PokemonSelectingItem {
@@ -39,13 +43,32 @@ class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)
const val WEAK_APRICORN_MULTIPLIER = 0.75F
}
override fun getName(stack: ItemStack): Component {
val quality = stack.get(CobblemonItemComponents.FLAVOUR)?.getQuality()
val baseNameKey = "item.cobblemon.aprijuice_${type.name.lowercase()}"
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
val stack = user.getItemInHand(hand)
val prefixKey = when (quality) {
CookingQuality.HIGH -> "item.cobblemon.aprijuice.prefix.delicious"
CookingQuality.MEDIUM -> "item.cobblemon.aprijuice.prefix.tasty"
val hasFlavour = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours?.any { it.value > 0 } == true
return if (!hasFlavour) {
// act like a drink :D
user.startUsingItem(hand)
InteractionResultHolder.consume(stack)
} else {
if (world is ServerLevel && user is ServerPlayer) {
return super<PokemonSelectingItem>.use(user, stack)
}
InteractionResultHolder.pass(stack)
}
}
override fun getName(stack: ItemStack): Component {
val flavourComponent = stack.get(CobblemonItemComponents.FLAVOUR)
val hasFlavour = flavourComponent?.flavours?.values?.any { it > 0 } == true
val quality = flavourComponent?.getQuality()
val baseNameKey = "item.cobblemon.aprijuice_${type.name.lowercase()}"
val prefixKey = when {
hasFlavour && quality == CookingQuality.HIGH -> "item.cobblemon.aprijuice.prefix.delicious"
hasFlavour && quality == CookingQuality.MEDIUM -> "item.cobblemon.aprijuice.prefix.tasty"
!hasFlavour -> "item.cobblemon.aprijuice.prefix.plain"
else -> null
}
@@ -56,7 +79,7 @@ class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)
)
} else {
Component.translatable(baseNameKey)
}
} // todo if no flavor call it "Plain Red Aprijuice" or "Raw Red Aprijuice" maybe and have players able to drink it
}
override fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
@@ -120,11 +143,35 @@ class AprijuiceItem(val type: Apricorn): CobblemonItem(Properties().stacksTo(16)
return value * apricornMultiplier * tasteMultiplier
}
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
if (world is ServerLevel && user is ServerPlayer) {
val stack = user.getItemInHand(hand)
return use(user, stack)
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
val hasFlavour = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours?.any { it.value > 0 } == true
if (!hasFlavour && user is Player && !world.isClientSide) {
user.foodData.eat(1, 0.1f)
if (!user.isCreative) {
stack.shrink(1)
}
}
return InteractionResultHolder.success(user.getItemInHand(hand))
return super.finishUsingItem(stack, world, user)
}
override fun getUseAnimation(stack: ItemStack): UseAnim {
val hasFlavour = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours?.any { it.value > 0 } == true
return if (hasFlavour) UseAnim.NONE else UseAnim.DRINK
}
override fun getUseDuration(stack: ItemStack, entity: LivingEntity): Int {
val hasFlavour = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours?.any { it.value > 0 } == true
return if (hasFlavour) 0 else 32 // 32 ticks like drinking a potion
}
// todo not sure which one is needed at the moment, but I assume just the eating sound?
override fun getDrinkingSound(): SoundEvent {
return SoundEvents.GENERIC_DRINK
}
override fun getEatingSound(): SoundEvent {
return SoundEvents.GENERIC_DRINK
}
}
@@ -0,0 +1,197 @@
/*
* 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
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.api.cooking.PokePuffUtils
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.pokemon.Nature
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResultHolder
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.UseAnim
import net.minecraft.world.level.Level
class PokePuffItem : Item(Properties().stacksTo(16)), PokemonSelectingItem {
override val bagItem = null
companion object {
const val LIKED_FLAVOR_MULTIPLIER = 10
const val DISLIKED_FLAVOR_MULTIPLIER = 7 // if they don't like it maybe have a bigger negative effect on the friendship? might make sense
}
override fun getName(stack: ItemStack): Component {
val dominantFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.getDominantFlavours()
val flavour = when {
dominantFlavours == null || dominantFlavours.isEmpty() -> "plain"
dominantFlavours.size > 1 -> "mild"
else -> dominantFlavours.first().name.lowercase()
}
val ingredients = stack.get(CobblemonItemComponents.INGREDIENT)
?.ingredientIds?.map { it.toString() } ?: emptyList()
val hasSugar = "minecraft:sugar" in ingredients
val hasSweet = ingredients.any {
it.startsWith("cobblemon:") && it.endsWith("_sweet")
}
val prefix = when {
hasSugar && hasSweet -> "deluxe"
hasSweet -> "fancy"
hasSugar -> "frosted"
else -> null
}
val isCreamPuff = (flavour == "plain")
val baseKey = if (isCreamPuff) "item.cobblemon.cream_puff" else "item.cobblemon.poke_puff"
val finalKey = if (prefix != null) "$baseKey.$prefix" else baseKey
return if (isCreamPuff) {
// No flavor inserted if it's Cream Puff
Component.translatable(finalKey)
} else {
// Insert flavor name for normal Poke Puffs
val flavourTranslationKey = "flavour.cobblemon.poke_puff.$flavour"
Component.translatable(finalKey, Component.translatable(flavourTranslationKey))
}
}
override fun use(world: Level, user: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
val stack = user.getItemInHand(hand)
val isPlain = getFlavorType(stack) == "plain"
return if (isPlain) {
if (!user.foodData.needsFood()) {
return InteractionResultHolder.fail(stack)
}
user.startUsingItem(hand)
InteractionResultHolder.consume(stack)
} else {
if (user is ServerPlayer) {
super<PokemonSelectingItem>.use(user, stack)
} else {
InteractionResultHolder.pass(stack)
}
}
}
override fun applyToPokemon(player: ServerPlayer, stack: ItemStack, pokemon: Pokemon): InteractionResultHolder<ItemStack> {
val friendshipChange = PokePuffUtils.calculateFriendshipChange(stack, pokemon.nature)
if (friendshipChange != 0) {
val current = pokemon.friendship
val newValue = (current + friendshipChange).coerceIn(0, 255)
if (newValue != current) {
pokemon.setFriendship(newValue)
pokemon.entity?.playSound(SoundEvents.PLAYER_BURP, 1F, 1F)
if (!player.isCreative) stack.shrink(1)
return InteractionResultHolder.success(stack)
}
}
return InteractionResultHolder.pass(stack)
}
private fun isPlainPuff(stack: ItemStack): Boolean {
val flavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: return true
return flavours.values.all { it == 0 }
}
private fun Nature.isNeutral(): Boolean {
return this.favouriteFlavour == this.dislikedFlavour
}
override fun getUseAnimation(stack: ItemStack): UseAnim {
val isPlain = isPlainPuff(stack)
return if (isPlain) UseAnim.EAT else UseAnim.NONE
}
override fun getUseDuration(stack: ItemStack, entity: LivingEntity): Int {
return if (getFlavorType(stack) == "plain") 32 else 0
}
override fun getEatingSound(): SoundEvent = SoundEvents.GENERIC_EAT
override fun getDrinkingSound(): SoundEvent = SoundEvents.GENERIC_EAT
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
if (!world.isClientSide && user is Player && getFlavorType(stack) == "plain") {
val ingredients = stack.get(CobblemonItemComponents.INGREDIENT)?.ingredientIds?.map { it.toString() } ?: emptyList()
val hasSugar = "minecraft:sugar" in ingredients
val hasSweet = ingredients.any { it.startsWith("cobblemon:") && it.endsWith("_sweet") }
val (nutrition, saturation) = when {
hasSugar && hasSweet -> 6 to 4f // deluxe
hasSweet -> 4 to 2.8f // fancy
hasSugar -> 3 to 2.4f // frosted
else -> 2 to 2f // plain
}
if (user.foodData.needsFood()) {
user.foodData.eat(nutrition, saturation)
if (!user.isCreative) {
stack.shrink(1)
}
}
}
return super.finishUsingItem(stack, world, user)
}
override fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
return getFriendshipDelta(stack, pokemon) != 0
}
private fun getFriendshipDelta(stack: ItemStack, pokemon: Pokemon): Int {
val flavour = getDominantFlavour(stack) ?: return 0
val nature = pokemon.nature
return when {
flavour == Flavour.MILD && nature.isNeutral() -> 5
flavour == nature.favouriteFlavour -> 10
flavour == nature.dislikedFlavour -> -10
else -> -10
}
}
private fun getDominantFlavour(stack: ItemStack): Flavour? {
val flavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: return null
val max = flavours.values.maxOrNull() ?: return null
val dominant = flavours.filterValues { it == max }.keys
return when {
dominant.isEmpty() -> null
dominant.size > 1 -> Flavour.MILD
else -> dominant.first()
}
}
private fun getFlavorType(stack: ItemStack): String {
val flavour = getDominantFlavour(stack)
return flavour?.name?.lowercase() ?: "plain"
}
}
@@ -12,6 +12,7 @@ import com.mojang.serialization.Codec
import io.netty.buffer.ByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.util.FastColor
import net.minecraft.world.item.DyeColor
/**
@@ -34,5 +35,9 @@ class FoodColourComponent(
colours.mapIndexed { index, value -> value == other.colours[index] }.all { it }
}
fun getColoursAsARGB(): List<Int> {
return colours.map { dye -> dye.textureDiffuseColor }
}
override fun hashCode() = colours.hashCode()
}
@@ -0,0 +1,38 @@
/*
* 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.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import io.netty.buffer.ByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
data class FoodComponent(
val hunger: Int,
val saturation: Float
) {
companion object {
val CODEC: Codec<FoodComponent> = RecordCodecBuilder.create { builder ->
builder.group(
Codec.INT.fieldOf("hunger").forGetter { it.hunger },
Codec.FLOAT.fieldOf("saturation").forGetter { it.saturation }
).apply(builder, ::FoodComponent)
}
val PACKET_CODEC: StreamCodec<ByteBuf, FoodComponent> = ByteBufCodecs.fromCodec(CODEC)
}
override fun equals(other: Any?): Boolean =
other is FoodComponent &&
hunger == other.hunger &&
saturation == other.saturation
override fun hashCode(): Int = 31 * hunger + saturation.hashCode()
}
@@ -0,0 +1,36 @@
/*
* 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.mojang.serialization.Codec
import io.netty.buffer.ByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.resources.ResourceLocation
/**
* Component for storing a list of main ingredient IDs.
*/
class IngredientComponent(
val ingredientIds: List<ResourceLocation>
) {
companion object {
val CODEC: Codec<IngredientComponent> = ResourceLocation.CODEC.listOf()
.xmap(::IngredientComponent, IngredientComponent::ingredientIds)
val PACKET_CODEC: StreamCodec<ByteBuf, IngredientComponent> =
ByteBufCodecs.fromCodec(CODEC)
}
override fun equals(other: Any?): Boolean {
return other is IngredientComponent && other.ingredientIds == this.ingredientIds
}
override fun hashCode() = ingredientIds.hashCode()
}
@@ -0,0 +1,36 @@
/*
* 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.api.cooking.SerializableMobEffectInstance
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import io.netty.buffer.ByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.world.effect.MobEffectInstance
data class MobEffectsComponent(
val mobEffects: List<MobEffectInstance>
) {
companion object {
val CODEC: Codec<MobEffectsComponent> = RecordCodecBuilder.create { builder ->
builder.group(
MobEffectInstance.CODEC.listOf().fieldOf("mob_effects").forGetter { it.mobEffects }
).apply(builder, ::MobEffectsComponent)
}
val PACKET_CODEC: StreamCodec<ByteBuf, MobEffectsComponent> = ByteBufCodecs.fromCodec(CODEC)
}
override fun equals(other: Any?): Boolean =
other is MobEffectsComponent && mobEffects == other.mobEffects
override fun hashCode(): Int = 31 * mobEffects.hashCode()
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.item.crafting
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.item.components.FlavourComponent
@@ -16,15 +17,26 @@ import net.minecraft.world.item.ItemStack
object FlavourSeasoningProcessor : SeasoningProcessor {
override val type = "flavour"
override fun apply(result: ItemStack, seasoning: List<ItemStack>) {
var flavours = mutableMapOf<Flavour, Int>()
val isPokePuff = result.`is`(CobblemonItems.POKE_PUFF)
val flavours = mutableMapOf<Flavour, Int>()
for (seasoningStack in seasoning) {
val seasoning = Seasonings.getFromItemStack(seasoningStack)
seasoning?.flavours?.forEach { (flavour, value) ->
val currentAmount = flavours[flavour] ?: 0
flavours[flavour] = currentAmount + value
val seasoningObj = Seasonings.getFromItemStack(seasoningStack) ?: continue
val relevantFlavours = if (isPokePuff) {
val maxValue = seasoningObj.flavours?.maxOfOrNull { it.value } ?: continue
seasoningObj.flavours.filterValues { it == maxValue } // keep all tied max flavours
} else {
seasoningObj.flavours ?: emptyMap()
}
for ((flavour, value) in relevantFlavours) {
flavours[flavour] = (flavours[flavour] ?: 0) + value
}
}
result.set(CobblemonItemComponents.FLAVOUR, FlavourComponent(flavours))
}
}
@@ -0,0 +1,39 @@
/*
* 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.crafting
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.cooking.FoodUtils
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.item.components.FoodComponent
import net.minecraft.core.component.DataComponents
import net.minecraft.world.item.ItemStack
import net.minecraft.world.effect.MobEffectInstance
object FoodSeasoningProcessor : SeasoningProcessor {
override val type = "food"
override fun apply(result: ItemStack, seasoning: List<ItemStack>) {
val foodData = result.get(DataComponents.FOOD)
val baseHunger = foodData?.nutrition ?: 0
val baseSaturation = foodData?.saturation ?: 0f
val foodComponents = seasoning.mapNotNull {
Seasonings.getFromItemStack(it)?.food?.toComponent()
}
if (foodComponents.isNotEmpty()) {
val merged = FoodUtils.merge(foodComponents, extraHunger = baseHunger, extraSaturation = baseSaturation)
result.set(CobblemonItemComponents.FOOD, merged)
} // we still want there to be food data on the output item still? To be conistent? idk
else {
result.set(CobblemonItemComponents.FOOD, FoodComponent(baseHunger, baseSaturation))
}
}
}
@@ -0,0 +1,31 @@
/*
* 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.crafting
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.item.components.IngredientComponent
import net.minecraft.world.item.ItemStack
object IngredientSeasoningProcessor : SeasoningProcessor {
override val type = "ingredient"
override fun apply(result: ItemStack, seasoning: List<ItemStack>) {
val ingredients = seasoning.mapNotNull { seasoningStack ->
val seasoningData = Seasonings.getFromItemStack(seasoningStack)
if (seasoningData != null) {
seasoningStack.item.builtInRegistryHolder().key().location()
} else null
}
if (ingredients.isNotEmpty()) {
result.set(CobblemonItemComponents.INGREDIENT, IngredientComponent(ingredients))
}
}
}
@@ -0,0 +1,33 @@
/*
* 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.crafting
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.cooking.MobEffectUtils
import com.cobblemon.mod.common.api.cooking.Seasonings
import com.cobblemon.mod.common.api.cooking.SerializableMobEffectInstance
import com.cobblemon.mod.common.item.components.MobEffectsComponent
import net.minecraft.world.item.ItemStack
import net.minecraft.world.effect.MobEffectInstance
object MobEffectSeasoningProcessor : SeasoningProcessor {
override val type = "mob_effects"
override fun apply(result: ItemStack, seasoning: List<ItemStack>) {
val allEffects: List<SerializableMobEffectInstance> = seasoning
.mapNotNull { Seasonings.getFromItemStack(it)?.mobEffects }
.flatMap { it.appliedEffects }
val mergedEffects = MobEffectUtils.mergeEffects(allEffects).map { it.toInstance() }
if (mergedEffects.isNotEmpty()) {
result.set(CobblemonItemComponents.MOB_EFFECTS, MobEffectsComponent(mergedEffects))
}
}
}
@@ -21,9 +21,12 @@ import net.minecraft.world.item.ItemStack
interface SeasoningProcessor {
companion object {
val processors = mutableMapOf<String, SeasoningProcessor>(
IngredientSeasoningProcessor.type to IngredientSeasoningProcessor,
BaitSeasoningProcessor.type to BaitSeasoningProcessor,
FlavourSeasoningProcessor.type to FlavourSeasoningProcessor,
FoodColourSeasoningProcessor.type to FoodColourSeasoningProcessor
FoodColourSeasoningProcessor.type to FoodColourSeasoningProcessor,
FoodSeasoningProcessor.type to FoodSeasoningProcessor,
MobEffectSeasoningProcessor.type to MobEffectSeasoningProcessor
)
}
@@ -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.item.food
import com.cobblemon.mod.common.CobblemonItemComponents
import net.minecraft.network.chat.Component
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.food.FoodProperties
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.UseAnim
import net.minecraft.world.level.Level
class PonigiriItem : Item(
Properties().stacksTo(16)
.food(FoodProperties.Builder()
.alwaysEdible()
.nutrition(2)
.saturationModifier(0.55f)
.build())
) {
override fun getName(stack: ItemStack): Component {
val ingredients = stack.get(CobblemonItemComponents.INGREDIENT)
?.ingredientIds?.map { it.toString() } ?: emptyList()
val hasSweetBerries = "minecraft:sweet_berries" in ingredients
val nameKey = when {
hasSweetBerries -> "item.cobblemon.jelly_doughnut"
else -> "item.cobblemon.ponigiri"
}
return Component.translatable(nameKey)
}
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
val effects = stack.get(CobblemonItemComponents.FOOD)
if (effects != null && !world.isClientSide) {
if (user is Player) { // todo maybe we want to be able to let other mobs eat these? or modded creatures that have hunder? idk
user.foodData.eat(effects.hunger, effects.saturation)
}
}
return super.finishUsingItem(stack, world, user)
}
override fun getUseAnimation(stack: ItemStack) = UseAnim.EAT
override fun getEatingSound(): SoundEvent {
return SoundEvents.GENERIC_EAT
}
}
@@ -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.item.food
import com.cobblemon.mod.common.CobblemonItemComponents
import net.minecraft.sounds.SoundEvent
import net.minecraft.sounds.SoundEvents
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.food.FoodProperties
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.UseAnim
import net.minecraft.world.level.Level
class SinisterTeaItem : Item(
Properties().stacksTo(16)
.food(FoodProperties.Builder()
.alwaysEdible()
.nutrition(0)
.saturationModifier(0.0f)
.build())
) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
if (!world.isClientSide) {
val effectsComponent = stack.get(CobblemonItemComponents.MOB_EFFECTS)
if (effectsComponent != null) {
for (effect in effectsComponent.mobEffects) {
val effectCopy = MobEffectInstance(effect)
user.addEffect(effectCopy)
}
}
}
return super.finishUsingItem(stack, world, user)
}
override fun getUseAnimation(stack: ItemStack) = UseAnim.DRINK
// todo not sure which one is needed at the moment, but I assume just the eating sound?
override fun getDrinkingSound(): SoundEvent {
return SoundEvents.GENERIC_DRINK
}
override fun getEatingSound(): SoundEvent {
return SoundEvents.GENERIC_DRINK
}
}
@@ -751,6 +751,7 @@
"item.cobblemon.aprijuice_white": "White Aprijuice",
"item.cobblemon.aprijuice_yellow": "Yellow Aprijuice",
"item.cobblemon.aprijuice.prefix.plain": "Plain",
"item.cobblemon.aprijuice.prefix.tasty": "Tasty",
"item.cobblemon.aprijuice.prefix.delicious": "Delicious",
"item.cobblemon.aprijuice.quality_format": "%1$s %2$s",
@@ -765,11 +766,16 @@
"cobblemon.tooltip.see_more_info": "Hold shift to see info",
"cobblemon.item_class.fishing_bait": "Bait Effects",
"cobblemon.item_class.seasoning": "Seasoning",
"cobblemon.item_class.mob_effect": "Mob Effects",
"cobblemon.item_class.food": "Food",
"cobblemon.cooking.cooking_quality": "Quality: %1$s",
"cobblemon.cooking.cooking_quality.low": "Low",
"cobblemon.cooking.cooking_quality.medium": "Medium",
"cobblemon.cooking.cooking_quality.high": "High",
"cobblemon.tooltip.food.hunger": "Hunger: %s",
"cobblemon.tooltip.food.saturation": "Saturation: %s",
"cobblemon.tooltip.mob_effect_entry": "%1$s %2$s (%3$s)",
"cobblemon.fossil.armor": "Armor",
"cobblemon.fossil.bird": "Bird",
@@ -993,6 +999,28 @@
"cobblemon.seasoning_flavor.bitter": "Bitter",
"cobblemon.seasoning_flavor.sour": "Sour",
"item.cobblemon.ponigiri": "Ponigiri",
"item.cobblemon.jelly_doughnut": "Jelly Donut",
"item.cobblemon.sinister_tea": "Sinister Tea",
"item.cobblemon.poke_puff": "%s Poke Puff",
"item.cobblemon.poke_puff.frosted": "Frosted %s Poke Puff",
"item.cobblemon.poke_puff.fancy": "Fancy %s Poke Puff",
"item.cobblemon.poke_puff.deluxe": "Deluxe %s Poke Puff",
"item.cobblemon.cream_puff": "Cream Puff",
"item.cobblemon.cream_puff.frosted": "Frosted Cream Puff",
"item.cobblemon.cream_puff.fancy": "Fancy Cream Puff",
"item.cobblemon.cream_puff.deluxe": "Deluxe Cream Puff",
"flavour.cobblemon.poke_puff.spicy": "Spicy",
"flavour.cobblemon.poke_puff.dry": "Dry",
"flavour.cobblemon.poke_puff.sweet": "Sweet",
"flavour.cobblemon.poke_puff.bitter": "Bitter",
"flavour.cobblemon.poke_puff.sour": "Sour",
"flavour.cobblemon.poke_puff.mild": "Mild",
"tooltip.cobblemon.poke_puff.nature.neutral": "Neutral",
"tooltip.cobblemon.poke_puff.friendship_increase": "+%1$s Friendship for %2$s natures",
"tooltip.cobblemon.poke_puff.friendship_decrease": "-%1$s Friendship for other natures",
"cobblemon.tooltip.poke_puff.friendship_effects": "Friendship Effects",
"entity.minecraft.villager.nurse": "Nurse",
"entity.minecraft.villager.cobblemon.nurse": "Nurse",
@@ -0,0 +1,722 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain"
},
"overrides": [
{
"predicate": {
"cobblemon:poke_puff_combined": 0.001
},
"model": "cobblemon:item/poke_puff_overlay_spicy"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.002
},
"model": "cobblemon:item/poke_puff_overlay_spicy_only"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.003
},
"model": "cobblemon:item/poke_puff_overlay_spicy_strawberry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.004
},
"model": "cobblemon:item/poke_puff_overlay_dry_only"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.005
},
"model": "cobblemon:item/poke_puff_overlay_spicy_love"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.006
},
"model": "cobblemon:item/poke_puff_overlay_sweet_only"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.007
},
"model": "cobblemon:item/poke_puff_overlay_spicy_berry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.008
},
"model": "cobblemon:item/poke_puff_overlay_bitter_only"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.009
},
"model": "cobblemon:item/poke_puff_overlay_spicy_ribbon"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.01
},
"model": "cobblemon:item/poke_puff_overlay_sour_only"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.011
},
"model": "cobblemon:item/poke_puff_overlay_spicy_clover"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.012
},
"model": "cobblemon:item/poke_puff_overlay_mild_only"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.013
},
"model": "cobblemon:item/poke_puff_overlay_spicy_flower"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.014
},
"model": "cobblemon:item/poke_puff_overlay_plain_only"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.015
},
"model": "cobblemon:item/poke_puff_overlay_spicy_star"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.016
},
"model": "cobblemon:item/poke_puff_overlay_dry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.017
},
"model": "cobblemon:item/poke_puff_overlay_dry_strawberry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.018
},
"model": "cobblemon:item/poke_puff_overlay_dry_love"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.019
},
"model": "cobblemon:item/poke_puff_overlay_dry_berry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.02
},
"model": "cobblemon:item/poke_puff_overlay_dry_ribbon"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.021
},
"model": "cobblemon:item/poke_puff_overlay_dry_clover"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.022
},
"model": "cobblemon:item/poke_puff_overlay_dry_flower"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.023
},
"model": "cobblemon:item/poke_puff_overlay_dry_star"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.024
},
"model": "cobblemon:item/poke_puff_overlay_sweet"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.025
},
"model": "cobblemon:item/poke_puff_overlay_sweet_strawberry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.026
},
"model": "cobblemon:item/poke_puff_overlay_sweet_love"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.027
},
"model": "cobblemon:item/poke_puff_overlay_sweet_berry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.028
},
"model": "cobblemon:item/poke_puff_overlay_sweet_ribbon"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.029
},
"model": "cobblemon:item/poke_puff_overlay_sweet_clover"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.03
},
"model": "cobblemon:item/poke_puff_overlay_sweet_flower"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.031
},
"model": "cobblemon:item/poke_puff_overlay_sweet_star"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.032
},
"model": "cobblemon:item/poke_puff_overlay_bitter"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.033
},
"model": "cobblemon:item/poke_puff_overlay_bitter_strawberry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.034
},
"model": "cobblemon:item/poke_puff_overlay_bitter_love"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.035
},
"model": "cobblemon:item/poke_puff_overlay_bitter_berry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.036
},
"model": "cobblemon:item/poke_puff_overlay_bitter_ribbon"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.037
},
"model": "cobblemon:item/poke_puff_overlay_bitter_clover"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.038
},
"model": "cobblemon:item/poke_puff_overlay_bitter_flower"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.039
},
"model": "cobblemon:item/poke_puff_overlay_bitter_star"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.04
},
"model": "cobblemon:item/poke_puff_overlay_sour"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.041
},
"model": "cobblemon:item/poke_puff_overlay_sour_strawberry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.042
},
"model": "cobblemon:item/poke_puff_overlay_sour_love"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.043
},
"model": "cobblemon:item/poke_puff_overlay_sour_berry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.044
},
"model": "cobblemon:item/poke_puff_overlay_sour_ribbon"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.045
},
"model": "cobblemon:item/poke_puff_overlay_sour_clover"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.046
},
"model": "cobblemon:item/poke_puff_overlay_sour_flower"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.047
},
"model": "cobblemon:item/poke_puff_overlay_sour_star"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.048
},
"model": "cobblemon:item/poke_puff_overlay_mild"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.049
},
"model": "cobblemon:item/poke_puff_overlay_mild_strawberry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.05
},
"model": "cobblemon:item/poke_puff_overlay_mild_love"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.051
},
"model": "cobblemon:item/poke_puff_overlay_mild_berry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.052
},
"model": "cobblemon:item/poke_puff_overlay_mild_ribbon"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.053
},
"model": "cobblemon:item/poke_puff_overlay_clover"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.054
},
"model": "cobblemon:item/poke_puff_overlay_mild_clover"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.055
},
"model": "cobblemon:item/poke_puff_overlay_flower"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.056
},
"model": "cobblemon:item/poke_puff_overlay_mild_flower"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.057
},
"model": "cobblemon:item/poke_puff_overlay_star"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.058
},
"model": "cobblemon:item/poke_puff_overlay_mild_star"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.059
},
"model": "cobblemon:item/poke_puff_overlay_plain"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.06
},
"model": "cobblemon:item/poke_puff_overlay_strawberry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.061
},
"model": "cobblemon:item/poke_puff_overlay_plain_strawberry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.062
},
"model": "cobblemon:item/poke_puff_overlay_love"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.063
},
"model": "cobblemon:item/poke_puff_overlay_plain_love"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.064
},
"model": "cobblemon:item/poke_puff_overlay_berry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.065
},
"model": "cobblemon:item/poke_puff_overlay_plain_berry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.066
},
"model": "cobblemon:item/poke_puff_overlay_ribbon"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.067
},
"model": "cobblemon:item/poke_puff_overlay_plain_ribbon"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.068
},
"model": "cobblemon:item/poke_puff_overlay_strawberry_spicy"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.069
},
"model": "cobblemon:item/poke_puff_overlay_strawberry_dry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.07
},
"model": "cobblemon:item/poke_puff_overlay_strawberry_sweet"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.071
},
"model": "cobblemon:item/poke_puff_overlay_strawberry_bitter"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.072
},
"model": "cobblemon:item/poke_puff_overlay_strawberry_sour"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.073
},
"model": "cobblemon:item/poke_puff_overlay_strawberry_mild"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.074
},
"model": "cobblemon:item/poke_puff_overlay_strawberry_plain"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.075
},
"model": "cobblemon:item/poke_puff_overlay_love_spicy"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.076
},
"model": "cobblemon:item/poke_puff_overlay_love_dry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.077
},
"model": "cobblemon:item/poke_puff_overlay_love_sweet"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.078
},
"model": "cobblemon:item/poke_puff_overlay_love_bitter"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.079
},
"model": "cobblemon:item/poke_puff_overlay_love_sour"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.08
},
"model": "cobblemon:item/poke_puff_overlay_love_mild"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.081
},
"model": "cobblemon:item/poke_puff_overlay_love_plain"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.082
},
"model": "cobblemon:item/poke_puff_overlay_berry_spicy"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.083
},
"model": "cobblemon:item/poke_puff_overlay_berry_dry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.084
},
"model": "cobblemon:item/poke_puff_overlay_berry_sweet"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.085
},
"model": "cobblemon:item/poke_puff_overlay_berry_bitter"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.086
},
"model": "cobblemon:item/poke_puff_overlay_berry_sour"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.087
},
"model": "cobblemon:item/poke_puff_overlay_berry_mild"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.088
},
"model": "cobblemon:item/poke_puff_overlay_berry_plain"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.089
},
"model": "cobblemon:item/poke_puff_overlay_ribbon_spicy"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.09
},
"model": "cobblemon:item/poke_puff_overlay_ribbon_dry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.091
},
"model": "cobblemon:item/poke_puff_overlay_ribbon_sweet"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.092
},
"model": "cobblemon:item/poke_puff_overlay_ribbon_bitter"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.093
},
"model": "cobblemon:item/poke_puff_overlay_ribbon_sour"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.094
},
"model": "cobblemon:item/poke_puff_overlay_ribbon_mild"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.095
},
"model": "cobblemon:item/poke_puff_overlay_ribbon_plain"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.096
},
"model": "cobblemon:item/poke_puff_overlay_clover_spicy"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.097
},
"model": "cobblemon:item/poke_puff_overlay_clover_dry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.098
},
"model": "cobblemon:item/poke_puff_overlay_clover_sweet"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.099
},
"model": "cobblemon:item/poke_puff_overlay_clover_bitter"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.1
},
"model": "cobblemon:item/poke_puff_overlay_clover_sour"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.101
},
"model": "cobblemon:item/poke_puff_overlay_clover_mild"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.102
},
"model": "cobblemon:item/poke_puff_overlay_clover_plain"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.103
},
"model": "cobblemon:item/poke_puff_overlay_flower_spicy"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.104
},
"model": "cobblemon:item/poke_puff_overlay_flower_dry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.105
},
"model": "cobblemon:item/poke_puff_overlay_flower_sweet"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.106
},
"model": "cobblemon:item/poke_puff_overlay_flower_bitter"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.107
},
"model": "cobblemon:item/poke_puff_overlay_flower_sour"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.108
},
"model": "cobblemon:item/poke_puff_overlay_flower_mild"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.109
},
"model": "cobblemon:item/poke_puff_overlay_flower_plain"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.11
},
"model": "cobblemon:item/poke_puff_overlay_star_spicy"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.111
},
"model": "cobblemon:item/poke_puff_overlay_star_dry"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.112
},
"model": "cobblemon:item/poke_puff_overlay_star_sweet"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.113
},
"model": "cobblemon:item/poke_puff_overlay_star_bitter"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.114
},
"model": "cobblemon:item/poke_puff_overlay_star_sour"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.115
},
"model": "cobblemon:item/poke_puff_overlay_star_mild"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.116
},
"model": "cobblemon:item/poke_puff_overlay_star_plain"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.117
},
"model": "cobblemon:item/poke_puff_overlay_plain_clover"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.118
},
"model": "cobblemon:item/poke_puff_overlay_plain_flower"
},
{
"predicate": {
"cobblemon:poke_puff_combined": 0.119
},
"model": "cobblemon:item/poke_puff_overlay_plain_star"
}
]
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_sour",
"layer1": "cobblemon:item/poke_puffs/overlay_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_spicy",
"layer1": "cobblemon:item/poke_puffs/overlay_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_sweet",
"layer1": "cobblemon:item/poke_puffs/overlay_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_bitter"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_bitter_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_bitter_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_bitter_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_bitter_love"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_bitter_ribbon"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_bitter_star"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_bitter_strawberry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_sour",
"layer1": "cobblemon:item/poke_puffs/overlay_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_spicy",
"layer1": "cobblemon:item/poke_puffs/overlay_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_sweet",
"layer1": "cobblemon:item/poke_puffs/overlay_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_dry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_dry_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_dry_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_dry_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_dry_love"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_dry_ribbon"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_dry_star"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_dry_strawberry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_sour",
"layer1": "cobblemon:item/poke_puffs/overlay_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_spicy",
"layer1": "cobblemon:item/poke_puffs/overlay_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_sweet",
"layer1": "cobblemon:item/poke_puffs/overlay_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_love"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_bitter",
"layer1": "cobblemon:item/poke_puffs/overlay_love"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_dry",
"layer1": "cobblemon:item/poke_puffs/overlay_love"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_love"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_love"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_sour",
"layer1": "cobblemon:item/poke_puffs/overlay_love"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_spicy",
"layer1": "cobblemon:item/poke_puffs/overlay_love"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_sweet",
"layer1": "cobblemon:item/poke_puffs/overlay_love"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_mild"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_mild_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_mild_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_mild_flower"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_mild_love"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_mild_ribbon"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_mild_star"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_mild",
"layer1": "cobblemon:item/poke_puffs/overlay_mild_strawberry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_plain"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_plain_berry"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_plain_clover"
}
}
@@ -0,0 +1,7 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "cobblemon:item/poke_puffs/poke_puff_base_plain",
"layer1": "cobblemon:item/poke_puffs/overlay_plain_flower"
}
}

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