From 436606abf465fe9133030f65660291b9afcb755f Mon Sep 17 00:00:00 2001
From: DBotThePony <dbotthepony@yandex.ru>
Date: Sun, 9 Mar 2025 21:11:42 +0700
Subject: [PATCH] Now Bread monster can spawn when thrown as item And when
 killed, inert version is dropped

---
 .../mc/otm/datagen/lang/English.kt            |  2 +
 .../mc/otm/datagen/lang/Russian.kt            |  2 +
 .../mc/otm/datagen/loot/EntityLoot.kt         | 11 +++++
 .../dbotthepony/mc/otm/entity/BreadMonster.kt |  3 ++
 .../item/consumables/ImperfectBreadItem.kt    | 41 ++++++++++++++++---
 .../mc/otm/registry/game/MCreativeTabs.kt     |  3 ++
 .../otm/registry/game/MDataComponentTypes.kt  |  3 ++
 7 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt
index f3f095f07..9dc45033e 100644
--- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt
+++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt
@@ -145,6 +145,8 @@ private fun sounds(provider: MatteryLanguageProvider) {
 
 private fun misc(provider: MatteryLanguageProvider) {
 	with(provider.english) {
+		misc("misc.inert", "Inert")
+
 		misc("misc.yes", "Yes")
 		misc("misc.no", "No")
 
diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt
index faf9ae2b1..9a8cfdc09 100644
--- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt
+++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt
@@ -159,6 +159,8 @@ private fun sounds(provider: MatteryLanguageProvider) {
 
 private fun misc(provider: MatteryLanguageProvider) {
 	with(provider.russian) {
+		misc("misc.inert", "Инертен")
+
 		misc("misc.yes", "Да")
 		misc("misc.no", "Нет")
 
diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/EntityLoot.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/EntityLoot.kt
index 16ce1b445..1988712d3 100644
--- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/EntityLoot.kt
+++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/EntityLoot.kt
@@ -1,7 +1,10 @@
 package ru.dbotthepony.mc.otm.datagen.loot
 
+import net.minecraft.world.level.storage.loot.functions.SetComponentsFunction
 import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
 import ru.dbotthepony.mc.otm.datagen.modLootTable
+import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
+import ru.dbotthepony.mc.otm.registry.game.MEntityTypes
 import ru.dbotthepony.mc.otm.registry.game.MItems
 
 fun addEntityLoot(loot: LootTables) {
@@ -18,4 +21,12 @@ fun addEntityLoot(loot: LootTables) {
 			setRolls(1)
 		}
 	}
+
+	loot.builder(LootContextParamSets.ENTITY, MEntityTypes.BREAD_MONSTER.defaultLootTable) {
+		lootPool {
+			item(MItems.IMPERFECT_BREAD) {
+				apply(SetComponentsFunction.setComponent(MDataComponentTypes.INERT, true))
+			}
+		}
+	}
 }
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt
index 512563d84..1303709cd 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt
@@ -21,8 +21,11 @@ import net.minecraft.world.entity.monster.Zombie
 import net.minecraft.world.entity.npc.Villager
 import net.minecraft.world.entity.player.Player
 import net.minecraft.world.level.Level
+import ru.dbotthepony.mc.otm.registry.game.MEntityTypes
 
 class BreadMonster(type: EntityType<BreadMonster>, level: Level) : Monster(type, level) {
+	constructor(level: Level) : this(MEntityTypes.BREAD_MONSTER, level)
+
 	val idleState = AnimationState()
 
 	init {
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt
index 0ad85e2ea..089de13fc 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt
@@ -1,16 +1,21 @@
 package ru.dbotthepony.mc.otm.item.consumables
 
+import net.minecraft.ChatFormatting
 import net.minecraft.server.level.ServerPlayer
 import net.minecraft.world.effect.MobEffectInstance
 import net.minecraft.world.effect.MobEffects
-import net.minecraft.world.level.Level
 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.entity.item.ItemEntity
 import net.minecraft.world.item.ItemStack
+import net.minecraft.world.level.Level
+import ru.dbotthepony.mc.otm.core.TranslatableComponent
+import ru.dbotthepony.mc.otm.core.otmRandom
+import ru.dbotthepony.mc.otm.core.position
+import ru.dbotthepony.mc.otm.entity.BreadMonster
+import ru.dbotthepony.mc.otm.item.MatteryItem
+import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
 
-class ImperfectBreadItem(properties: Item.Properties) : Item(properties) {
+class ImperfectBreadItem(properties: Properties) : MatteryItem(properties) {
 	override fun finishUsingItem(stack: ItemStack, level: Level, entity: LivingEntity): ItemStack {
 		if (entity is ServerPlayer) {
 			entity.addEffect(MobEffectInstance(MobEffects.POISON, 80, 2))
@@ -18,4 +23,30 @@ class ImperfectBreadItem(properties: Item.Properties) : Item(properties) {
 
 		return super.finishUsingItem(stack, level, entity)
 	}
+
+	init {
+		tooltips.addNormal { itemStack, context, acceptor ->
+			if (itemStack[MDataComponentTypes.INERT] == true) {
+				acceptor(TranslatableComponent("otm.misc.inert").withStyle(ChatFormatting.DARK_GRAY))
+			}
+		}
+	}
+
+	override fun onEntityItemUpdate(stack: ItemStack, entity: ItemEntity): Boolean {
+		if (stack[MDataComponentTypes.INERT] == true)
+			return super.onEntityItemUpdate(stack, entity)
+
+		// roll multiple times so multiple bread monsters can spawn on tick
+		// and also chance be less biased
+		for (i in 0 until stack.count.coerceAtMost(16)) {
+			if (entity.level().otmRandom.nextFloat() < 0.001f) {
+				val ent = BreadMonster(entity.level())
+				ent.position = entity.position
+				entity.level().addFreshEntity(ent)
+				stack.shrink(1)
+			}
+		}
+
+		return super.onEntityItemUpdate(stack, entity)
+	}
 }
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MCreativeTabs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MCreativeTabs.kt
index 0d13a7607..4d1f4f08d 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MCreativeTabs.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MCreativeTabs.kt
@@ -287,6 +287,9 @@ private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
 
 		accept(MItems.NUTRIENT_PASTE)
 		accept(MItems.IMPERFECT_BREAD)
+		accept(ItemStack(MItems.IMPERFECT_BREAD).also {
+			it[MDataComponentTypes.INERT] = true
+		})
 
 		// exo
 		accept(MItems.EXOPACK_PROBE)
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt
index 1817fed3a..4459e52e0 100644
--- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList
 import com.mojang.serialization.Codec
 import net.minecraft.core.UUIDUtil
 import net.minecraft.core.component.DataComponentType
+import net.minecraft.core.component.DataComponents
 import net.minecraft.core.registries.BuiltInRegistries
 import net.minecraft.nbt.CompoundTag
 import net.minecraft.network.RegistryFriendlyByteBuf
@@ -69,6 +70,8 @@ object MDataComponentTypes {
 	val MAX_BATTERY_OUTPUT: DataComponentType<Decimal> by registry.register("max_battery_output") { DecimalComponent() }
 	val MATTER_LEVEL: DataComponentType<Decimal> by registry.register("matter_level") { DecimalComponent() }
 
+	val INERT: DataComponentType<Boolean> by registry.register("inert") { DataComponentType.builder<Boolean>().persistent(Codec.BOOL).build() }
+
 	val EXOPACK_SLOT_COUNT: DataComponentType<Int> by registry.register("exopack_slot_count") { DataComponentType.builder<Int>().persistent(Codec.INT).networkSynchronized(StreamCodecs.INT).build() }
 	val EXOPACK_UPGRADE_ID: DataComponentType<UUID> by registry.register("exopack_upgrade_id") { uuid() }
 	val QUANTUM_LINK_ID: DataComponentType<UUID> by registry.register("quantum_link_id") { uuid() }