199 lines
6.3 KiB
Java
199 lines
6.3 KiB
Java
package com.tiedup.remake.entities;
|
|
|
|
import com.tiedup.remake.core.SystemMessageManager;
|
|
import com.tiedup.remake.v2.bondage.CollarHelper;
|
|
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import com.tiedup.remake.state.PlayerBindState;
|
|
import com.tiedup.remake.util.MessageDispatcher;
|
|
import com.tiedup.remake.util.teleport.Position;
|
|
import com.tiedup.remake.util.time.Timer;
|
|
import com.tiedup.remake.v2.BodyRegionV2;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.UUID;
|
|
import net.minecraft.ChatFormatting;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
|
|
/**
|
|
* Handles the bondage service system for TiedUp NPCs.
|
|
* When enabled via collar settings, players who attack the NPC
|
|
* will be captured and teleported to the configured prison.
|
|
*
|
|
* <p>Flow:
|
|
* <ul>
|
|
* <li>First hit: Warning message + 10 second timer</li>
|
|
* <li>Second hit within timer: Capture and teleport to prison</li>
|
|
* </ul>
|
|
*
|
|
* <p>This system is transient - serviceTargets are not persisted.
|
|
*/
|
|
public class BondageServiceHandler {
|
|
|
|
private static final String DEFAULT_MESSAGE =
|
|
"Hello! Would you like to be tied up in my owner's prison?";
|
|
private static final int WARNING_TIMER_SECONDS = 10;
|
|
|
|
private final AbstractTiedUpNpc npc;
|
|
private final Map<UUID, Timer> serviceTargets = new HashMap<>();
|
|
|
|
public BondageServiceHandler(AbstractTiedUpNpc npc) {
|
|
this.npc = npc;
|
|
}
|
|
|
|
/**
|
|
* Check if bondage service is enabled for this damsel.
|
|
* Requires: collar with bondage service flag ON and cell assigned.
|
|
*
|
|
* @return true if bondage service is active
|
|
*/
|
|
public boolean isEnabled() {
|
|
if (!npc.hasCollar()) return false;
|
|
|
|
ItemStack collar = npc.getEquipment(BodyRegionV2.NECK);
|
|
return (
|
|
CollarHelper.hasCellAssigned(collar) &&
|
|
CollarHelper.isBondageServiceEnabled(collar)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get the custom bondage service message from the collar.
|
|
*
|
|
* @return Custom message or default message
|
|
*/
|
|
public String getMessage() {
|
|
if (npc.hasCollar()) {
|
|
ItemStack collar = npc.getEquipment(BodyRegionV2.NECK);
|
|
String message = CollarHelper.getServiceSentence(collar);
|
|
if (message != null && !message.isEmpty()) {
|
|
return message;
|
|
}
|
|
}
|
|
return DEFAULT_MESSAGE;
|
|
}
|
|
|
|
/**
|
|
* Handle a player attack on the damsel.
|
|
* If bondage service is enabled, intercepts the attack.
|
|
*
|
|
* @param player The attacking player
|
|
* @return true if the attack was intercepted (damage should be cancelled)
|
|
*/
|
|
public boolean handlePlayerAttack(Player player) {
|
|
if (player == null || npc.isTiedUp() || !isEnabled()) {
|
|
return false;
|
|
}
|
|
|
|
UUID playerID = player.getUUID();
|
|
Timer timer = serviceTargets.get(playerID);
|
|
|
|
if (timer != null && !timer.isExpired()) {
|
|
// SECOND HIT - Capture!
|
|
capturePlayer(player);
|
|
serviceTargets.remove(playerID);
|
|
} else {
|
|
// FIRST HIT - Warning
|
|
String message = getMessage() + " Hit me again!";
|
|
MessageDispatcher.talkTo(npc, player, message);
|
|
serviceTargets.put(
|
|
playerID,
|
|
new Timer(WARNING_TIMER_SECONDS, npc.level())
|
|
);
|
|
}
|
|
|
|
return true; // Attack intercepted
|
|
}
|
|
|
|
/**
|
|
* Capture a player and teleport them to the configured cell.
|
|
*
|
|
* @param player The player to capture
|
|
*/
|
|
private void capturePlayer(Player player) {
|
|
ItemStack collar = npc.getEquipment(BodyRegionV2.NECK);
|
|
if (!CollarHelper.isCollar(collar)) return;
|
|
|
|
java.util.UUID cellId = CollarHelper.getCellId(collar);
|
|
if (cellId == null) return;
|
|
|
|
// Get cell position from registry
|
|
if (
|
|
!(npc.level() instanceof
|
|
net.minecraft.server.level.ServerLevel serverLevel)
|
|
) return;
|
|
com.tiedup.remake.cells.CellDataV2 cell =
|
|
com.tiedup.remake.cells.CellRegistryV2.get(serverLevel).getCell(
|
|
cellId
|
|
);
|
|
if (cell == null) return;
|
|
|
|
Position cellPosition = new Position(
|
|
cell.getSpawnPoint().above(),
|
|
serverLevel.dimension()
|
|
);
|
|
|
|
// Warn masters if configured
|
|
warnOwners(player, collar);
|
|
|
|
// Get player's kidnapped state
|
|
PlayerBindState state = PlayerBindState.getInstance(player);
|
|
if (state != null) {
|
|
// Apply bondage
|
|
state.equip(
|
|
BodyRegionV2.ARMS,
|
|
DataDrivenBondageItem.createStack(ResourceLocation.fromNamespaceAndPath("tiedup", "ropes"))
|
|
);
|
|
state.equip(
|
|
BodyRegionV2.MOUTH,
|
|
DataDrivenBondageItem.createStack(ResourceLocation.fromNamespaceAndPath("tiedup", "ball_gag"))
|
|
);
|
|
|
|
// Teleport to cell
|
|
state.teleportToPosition(cellPosition);
|
|
|
|
// Tie to pole if configured on collar
|
|
if (CollarHelper.shouldTieToPole(collar)) {
|
|
state.tieToClosestPole(3);
|
|
}
|
|
}
|
|
|
|
// Announce capture
|
|
MessageDispatcher.talkTo(npc, player, "Welcome to my owner's cell!");
|
|
}
|
|
|
|
/**
|
|
* Warn collar owners about a capture via bondage service.
|
|
*
|
|
* @param capturedPlayer The player who was captured
|
|
* @param itemCollar The collar item
|
|
* @param collarStack The collar ItemStack
|
|
*/
|
|
private void warnOwners(
|
|
Player capturedPlayer,
|
|
ItemStack collarStack
|
|
) {
|
|
if (!CollarHelper.shouldWarnMasters(collarStack)) {
|
|
return;
|
|
}
|
|
|
|
String message =
|
|
npc.getNpcName() +
|
|
" captured " +
|
|
capturedPlayer.getName().getString() +
|
|
" via bondage service!";
|
|
|
|
for (UUID ownerUUID : CollarHelper.getOwners(collarStack)) {
|
|
Player owner = npc.level().getPlayerByUUID(ownerUUID);
|
|
if (owner != null) {
|
|
SystemMessageManager.sendChatToPlayer(
|
|
owner,
|
|
message,
|
|
ChatFormatting.GOLD
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|