package com.tiedup.remake.state.struggle; import com.tiedup.remake.core.SystemMessageManager.MessageCategory; import com.tiedup.remake.core.TiedUpMod; import com.tiedup.remake.items.base.ItemCollar; import com.tiedup.remake.state.PlayerBindState; import com.tiedup.remake.v2.BodyRegionV2; import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; /** * Phase 8: Master-Slave Relationships * * Struggle mechanics specifically for locked collars. * * How it Works: * - Only locked collars can be struggled against * - Success: Collar becomes UNLOCKED (not removed) * - No items are dropped (unlike bind struggle) * - Uses collar-specific GameRules for probability and resistance * * Differences from StruggleBinds: * - Condition: hasLockedCollar() instead of isTiedUp() * - Success: unlock collar instead of untie + drop items * - Resistance source: collar NBT instead of bind NBT * - GameRules: STRUGGLE_COLLAR, PROBABILITY_STRUGGLE_COLLAR, etc. * * Usage: * - Slave wears locked collar * - Presses R (struggle key) * - Eventually unlocks collar (can then remove it) * * @see StruggleBinds * @see StruggleState */ public class StruggleCollar extends StruggleState { /** * Get the current resistance from the equipped collar. * * @param state The PlayerBindState * @return Current collar resistance, or 0 if no collar */ @Override protected int getResistanceState(PlayerBindState state) { Player player = state.getPlayer(); ItemStack collar = V2EquipmentHelper.getInRegion(player, BodyRegionV2.NECK); if ( collar.isEmpty() || !(collar.getItem() instanceof ItemCollar collarItem) ) { return 0; } return collarItem.getCurrentResistance(collar, player); } /** * Set the current resistance on the equipped collar. * * @param state The PlayerBindState * @param resistance The new resistance value */ @Override protected void setResistanceState(PlayerBindState state, int resistance) { Player player = state.getPlayer(); ItemStack collar = V2EquipmentHelper.getInRegion(player, BodyRegionV2.NECK); if ( collar.isEmpty() || !(collar.getItem() instanceof ItemCollar collarItem) ) { return; } collarItem.setCurrentResistance(collar, resistance); } /** * Check if the collar can be struggled against. * * Conditions: * - Must have collar equipped * - Collar must be LOCKED * - Collar must allow struggle (canBeStruggledOut) * * Note: Can struggle collar even if NOT tied up. * * @param state The PlayerBindState * @return true if can struggle collar */ @Override protected boolean canStruggle(PlayerBindState state) { Player player = state.getPlayer(); // Phase 13 logic: Can only struggle against collar if NOT tied up if (state.isTiedUp()) { return false; } ItemStack collar = V2EquipmentHelper.getInRegion(player, BodyRegionV2.NECK); if ( collar.isEmpty() || !(collar.getItem() instanceof ItemCollar collarItem) ) { TiedUpMod.LOGGER.debug("[StruggleCollar] No collar equipped"); return false; } // Check if locked if (!collarItem.isLocked(collar)) { TiedUpMod.LOGGER.debug("[StruggleCollar] Collar is not locked"); return false; } // Check if struggle is enabled if (!collarItem.canBeStruggledOut(collar)) { TiedUpMod.LOGGER.debug( "[StruggleCollar] Collar struggle is disabled" ); return false; } return true; } /** * Action to perform when struggle is attempted. * Used for random shock chance on shock collars. */ @Override protected boolean onAttempt(PlayerBindState state) { Player player = state.getPlayer(); ItemStack collar = V2EquipmentHelper.getInRegion(player, BodyRegionV2.NECK); if ( !collar.isEmpty() && collar.getItem() instanceof com.tiedup.remake.items.ItemShockCollar shockCollar ) { return shockCollar.notifyStruggle(player, collar); } return true; } /** * Action to perform when struggle succeeds (resistance = 0). * * For collars: Unlock the collar. * The player can then manually remove it. * * @param state The PlayerBindState */ @Override protected void successAction(PlayerBindState state) { Player player = state.getPlayer(); ItemStack collar = V2EquipmentHelper.getInRegion(player, BodyRegionV2.NECK); if ( collar.isEmpty() || !(collar.getItem() instanceof ItemCollar collarItem) ) { TiedUpMod.LOGGER.warn( "[StruggleCollar] successAction called but no collar equipped" ); return; } // Unlock the collar collarItem.setLocked(collar, false); TiedUpMod.LOGGER.info( "[StruggleCollar] {} unlocked their collar!", player.getName().getString() ); // Note: Collar is NOT removed, just unlocked // Player can now manually remove it } @Override protected MessageCategory getSuccessCategory() { return MessageCategory.STRUGGLE_COLLAR_SUCCESS; } @Override protected MessageCategory getFailCategory() { return MessageCategory.STRUGGLE_COLLAR_FAIL; } /** * Tighten the collar (restore resistance to base value). * Called when a master tightens the slave's collar. * * Conditions: * - Collar must be locked * - Tightener must be different from wearer * * @param tightener The player tightening the collar * @param state The PlayerBindState of the collar wearer */ public void tighten(Player tightener, PlayerBindState state) { Player target = state.getPlayer(); if (tightener == null || target == null) { return; } // Can't tighten your own collar if (tightener.getUUID().equals(target.getUUID())) { TiedUpMod.LOGGER.debug( "[StruggleCollar] Cannot tighten own collar" ); return; } ItemStack collar = V2EquipmentHelper.getInRegion(target, BodyRegionV2.NECK); if ( collar.isEmpty() || !(collar.getItem() instanceof ItemCollar collarItem) ) { TiedUpMod.LOGGER.debug("[StruggleCollar] No collar to tighten"); return; } // Check if collar is locked if (!collarItem.isLocked(collar)) { TiedUpMod.LOGGER.debug( "[StruggleCollar] Collar must be locked to tighten" ); return; } // Get base resistance from GameRules int baseResistance = collarItem.getBaseResistance(target); int currentResistance = collarItem.getCurrentResistance(collar, target); // Only tighten if current resistance is lower than base if (currentResistance >= baseResistance) { TiedUpMod.LOGGER.debug( "[StruggleCollar] Collar already at max resistance" ); return; } // Restore to base resistance collarItem.setCurrentResistance(collar, baseResistance); TiedUpMod.LOGGER.info( "[StruggleCollar] {} tightened {}'s collar (resistance {} -> {})", tightener.getName().getString(), target.getName().getString(), currentResistance, baseResistance ); } }