package com.tiedup.remake.items; import com.tiedup.remake.core.ModConfig; import com.tiedup.remake.core.SettingsAccessor; import com.tiedup.remake.core.SystemMessageManager; import com.tiedup.remake.core.TiedUpMod; import com.tiedup.remake.state.IRestrainable; import com.tiedup.remake.state.PlayerBindState; import com.tiedup.remake.util.KidnappedHelper; import java.util.List; import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; 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.TooltipFlag; import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; /** * Rag - Can be soaked in chloroform to knock out targets * Has wet/dry state managed via NBT. * * * Usage: * 1. Hold chloroform bottle, rag in offhand, right-click → rag becomes wet * 2. Hold wet rag, right-click target → apply chloroform effect * 3. Wet rag evaporates over time (configurable) * * Effects on target: * - Slowness 127 (cannot move) * - Blindness * - Nausea * - UNCONSCIOUS pose */ public class ItemRag extends Item { private static final String NBT_WET = "wet"; private static final String NBT_WET_TIME = "wetTime"; // Ticks remaining public ItemRag() { super(new Item.Properties().stacksTo(16)); } @Override public void appendHoverText( ItemStack stack, @Nullable Level level, List tooltip, TooltipFlag flag ) { if (isWet(stack)) { int ticksRemaining = getWetTime(stack); int secondsRemaining = ticksRemaining / 20; tooltip.add( Component.literal("Soaked with chloroform").withStyle( ChatFormatting.GREEN ) ); tooltip.add( Component.literal( "Evaporates in: " + secondsRemaining + "s" ).withStyle(ChatFormatting.GRAY) ); } else { tooltip.add( Component.literal("Dry - needs chloroform").withStyle( ChatFormatting.GRAY ) ); } } /** * Called when player right-clicks another entity with the rag. * If wet, applies chloroform effect to the target. */ @Override public InteractionResult interactLivingEntity( ItemStack stack, Player player, LivingEntity target, InteractionHand hand ) { // Only run on server side if (player.level().isClientSide) { return InteractionResult.SUCCESS; } // Must be wet to apply chloroform if (!isWet(stack)) { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.RAG_DRY ); return InteractionResult.PASS; } // Apply chloroform to target applyChloroformToTarget(target, player); // The rag stays wet (can be used multiple times until it evaporates) TiedUpMod.LOGGER.info( "[ItemRag] {} applied chloroform to {}", player.getName().getString(), target.getName().getString() ); return InteractionResult.SUCCESS; } /** * Tick the rag to handle evaporation of wet state. */ @Override public void inventoryTick( ItemStack stack, Level level, Entity entity, int slot, boolean selected ) { if (level.isClientSide) return; if (isWet(stack)) { int wetTime = getWetTime(stack); if (wetTime > 0) { setWetTime(stack, wetTime - 1); } else { // Evaporated setWet(stack, false); if (entity instanceof Player player) { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.RAG_EVAPORATED ); } TiedUpMod.LOGGER.debug("[ItemRag] Chloroform evaporated"); } } } /** * Apply chloroform effect to a target. * Effects: Slowness 127, Blindness, Nausea for configured duration. * * @param target The target entity * @param player The player applying chloroform */ private void applyChloroformToTarget(LivingEntity target, Player player) { // Get duration from config via SettingsAccessor (single source of truth) int duration = SettingsAccessor.getChloroformDuration(); // Apply effects // Slowness 127 = cannot move at all target.addEffect( new MobEffectInstance( MobEffects.MOVEMENT_SLOWDOWN, duration, 127, false, false ) ); // Blindness target.addEffect( new MobEffectInstance( MobEffects.BLINDNESS, duration, 0, false, false ) ); // Nausea (confusion) target.addEffect( new MobEffectInstance( MobEffects.CONFUSION, duration, 0, false, false ) ); // Weakness (cannot fight back) target.addEffect( new MobEffectInstance( MobEffects.WEAKNESS, duration, 127, false, false ) ); // If target is IRestrainable, call applyChloroform to apply effects IRestrainable kidnapped = KidnappedHelper.getKidnappedState(target); if (kidnapped != null) { kidnapped.applyChloroform(duration); } TiedUpMod.LOGGER.debug( "[ItemRag] Applied chloroform to target for {} seconds", duration ); } // ========== Wet/Dry State Management ========== /** * Check if this rag is soaked with chloroform. * @param stack The item stack * @return true if wet with chloroform */ public static boolean isWet(ItemStack stack) { if (stack.isEmpty()) return false; CompoundTag tag = stack.getTag(); return tag != null && tag.getBoolean(NBT_WET); } /** * Set the wet state of this rag. * @param stack The item stack * @param wet true to make wet, false for dry */ public static void setWet(ItemStack stack, boolean wet) { if (stack.isEmpty()) return; stack.getOrCreateTag().putBoolean(NBT_WET, wet); if (!wet) { // Clear wet time when drying stack.getOrCreateTag().remove(NBT_WET_TIME); } } /** * Get the remaining wet time in ticks. * @param stack The item stack * @return Ticks remaining, or 0 if not wet */ public static int getWetTime(ItemStack stack) { if (stack.isEmpty()) return 0; CompoundTag tag = stack.getTag(); return tag != null ? tag.getInt(NBT_WET_TIME) : 0; } /** * Set the remaining wet time in ticks. * @param stack The item stack * @param ticks Ticks remaining */ public static void setWetTime(ItemStack stack, int ticks) { if (stack.isEmpty()) return; stack.getOrCreateTag().putInt(NBT_WET_TIME, ticks); } /** * Soak this rag with chloroform. * Sets wet = true and initializes the evaporation timer. * * @param stack The item stack * @param wetTime Time in ticks before evaporation */ public static void soak(ItemStack stack, int wetTime) { if (stack.isEmpty()) return; setWet(stack, true); setWetTime(stack, wetTime); TiedUpMod.LOGGER.debug( "[ItemRag] Soaked with chloroform ({} ticks)", wetTime ); } /** * Get the default wet time for soaking. * @return Default wet time in ticks */ public static int getDefaultWetTime() { return ModConfig.SERVER.ragWetTime.get(); } }