package com.tiedup.remake.items; import com.tiedup.remake.core.SystemMessageManager; import com.tiedup.remake.core.TiedUpMod; import com.tiedup.remake.items.base.ILockable; import com.tiedup.remake.state.IBondageState; import com.tiedup.remake.util.KidnappedHelper; import com.tiedup.remake.util.TiedUpSounds; import com.tiedup.remake.v2.BodyRegionV2; import java.util.UUID; import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; 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.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; /** * Master Key - Universal key that opens any padlock. * * * Behavior: * - Right-click: Opens Slave Management GUI (can unlock any lock) * - Shift+Right-click: Quick unlock all restraints on target * - Does not consume the key (reusable) * - Cannot lock items (unlock only) */ public class ItemMasterKey extends Item { public ItemMasterKey() { super(new Item.Properties().stacksTo(8)); } /** * Called when player right-clicks another entity with the master key. * Opens the Slave Item Management GUI or quick-unlocks all if sneaking. * * @param stack The item stack * @param player The player using the key * @param target The entity being interacted with * @param hand The hand holding the key * @return SUCCESS if action taken, PASS otherwise */ @Override public InteractionResult interactLivingEntity( ItemStack stack, Player player, LivingEntity target, InteractionHand hand ) { // Check if target can be restrained IBondageState targetState = KidnappedHelper.getKidnappedState(target); if (targetState == null) { return InteractionResult.PASS; } // Target must have a collar if (!targetState.hasCollar()) { if (!player.level().isClientSide) { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.ERROR, "Target is not wearing a collar!" ); } return InteractionResult.FAIL; } // Server-side: Handle Shift+click quick unlock if (!player.level().isClientSide) { if (player.isShiftKeyDown()) { // Quick unlock all - original behavior int unlocked = unlockAllRestraints(targetState, target); if (unlocked > 0) { TiedUpSounds.playUnlockSound(target); SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.INFO, "Unlocked " + unlocked + " restraint(s) on " + target.getName().getString() ); TiedUpMod.LOGGER.info( "[ItemMasterKey] {} quick-unlocked {} restraints on {}", player.getName().getString(), unlocked, target.getName().getString() ); } else { SystemMessageManager.sendToPlayer( player, SystemMessageManager.MessageCategory.INFO, "No locked restraints found" ); } return InteractionResult.SUCCESS; } // Normal click - validation only, client opens GUI return InteractionResult.SUCCESS; } // Client-side: Open GUI (normal click only) if (!player.isShiftKeyDown()) { openUnifiedBondageScreen(target); } return InteractionResult.SUCCESS; } /** * Opens the UnifiedBondageScreen in master mode targeting a specific entity. * * @param target The living entity to manage bondage for */ @OnlyIn(Dist.CLIENT) private void openUnifiedBondageScreen( net.minecraft.world.entity.LivingEntity target ) { net.minecraft.client.Minecraft.getInstance().setScreen( new com.tiedup.remake.client.gui.screens.UnifiedBondageScreen( target ) ); } /** * Unlock all locked restraints on the target. * Uses setLockedByKeyUUID(null) to properly clear the lock. * Optionally drops padlocks if the item's dropLockOnUnlock() returns true. * * @param targetState The target's IBondageState state * @param target The target entity (for dropping items) * @return Number of items unlocked */ private int unlockAllRestraints( IBondageState targetState, LivingEntity target ) { int unlocked = 0; // Unlock bind ItemStack bind = targetState.getEquipment(BodyRegionV2.ARMS); if (!bind.isEmpty() && bind.getItem() instanceof ILockable lockable) { if (lockable.isLocked(bind)) { lockable.setLockedByKeyUUID(bind, null); // Clear lock with keyUUID system unlocked++; if (lockable.dropLockOnUnlock()) { dropPadlock(targetState); } } } // Unlock gag ItemStack gag = targetState.getEquipment(BodyRegionV2.MOUTH); if (!gag.isEmpty() && gag.getItem() instanceof ILockable lockable) { if (lockable.isLocked(gag)) { lockable.setLockedByKeyUUID(gag, null); unlocked++; if (lockable.dropLockOnUnlock()) { dropPadlock(targetState); } } } // Unlock blindfold ItemStack blindfold = targetState.getEquipment(BodyRegionV2.EYES); if ( !blindfold.isEmpty() && blindfold.getItem() instanceof ILockable lockable ) { if (lockable.isLocked(blindfold)) { lockable.setLockedByKeyUUID(blindfold, null); unlocked++; if (lockable.dropLockOnUnlock()) { dropPadlock(targetState); } } } // Unlock earplugs ItemStack earplugs = targetState.getEquipment(BodyRegionV2.EARS); if ( !earplugs.isEmpty() && earplugs.getItem() instanceof ILockable lockable ) { if (lockable.isLocked(earplugs)) { lockable.setLockedByKeyUUID(earplugs, null); unlocked++; if (lockable.dropLockOnUnlock()) { dropPadlock(targetState); } } } // Unlock collar ItemStack collar = targetState.getEquipment(BodyRegionV2.NECK); if ( !collar.isEmpty() && collar.getItem() instanceof ILockable lockable ) { if (lockable.isLocked(collar)) { lockable.setLockedByKeyUUID(collar, null); unlocked++; if (lockable.dropLockOnUnlock()) { dropPadlock(targetState); } } } // Unlock mittens ItemStack mittens = targetState.getEquipment(BodyRegionV2.HANDS); if ( !mittens.isEmpty() && mittens.getItem() instanceof ILockable lockable ) { if (lockable.isLocked(mittens)) { lockable.setLockedByKeyUUID(mittens, null); unlocked++; if (lockable.dropLockOnUnlock()) { dropPadlock(targetState); } } } return unlocked; } /** * Drop a padlock item near the target. * * @param targetState The target's IBondageState state */ private void dropPadlock(IBondageState targetState) { // Create a padlock item to drop ItemStack padlock = new ItemStack( com.tiedup.remake.items.ModItems.PADLOCK.get() ); targetState.kidnappedDropItem(padlock); } }