Phase 1 (state): PlayerBindState, PlayerCaptorManager, PlayerEquipment, PlayerDataRetrieval, PlayerLifecycle, PlayerShockCollar, StruggleAccessory Phase 2 (client): AnimationTickHandler, NpcAnimationTickHandler, 5 render handlers, DamselModel, 3 client mixins, SelfBondageInputHandler, SlaveManagementScreen, ActionPanel, SlaveEntryWidget, ModKeybindings Phase 3 (entities): 28 entity/AI files migrated to CollarHelper, BindModeHelper, PoseTypeHelper, createStack() Phase 4 (network): PacketSlaveAction, PacketMasterEquip, PacketAssignCellToCollar, PacketNpcCommand, PacketFurnitureForcemount Phase 5 (events): RestraintTaskTickHandler, PetPlayRestrictionHandler, PlayerEnslavementHandler, ChatEventHandler, LaborAttackPunishmentHandler Phase 6 (commands): BondageSubCommand, CollarCommand, NPCCommand, KidnapSetCommand Phase 7 (compat): MCAKidnappedAdapter, MCA mixins Phase 8 (misc): GagTalkManager, PetRequestManager, HangingCagePiece, BondageItemBlockEntity, TrappedChestBlockEntity, DispenserBehaviors, BondageItemLoaderUtility, RestraintApplicator, StruggleSessionManager, MovementStyleResolver, CampLifecycleManager Some files retain dual V1/V2 checks (instanceof V1 || V2Helper) for coexistence — V1-only branches removed in Branch D.
763 lines
25 KiB
Java
763 lines
25 KiB
Java
package com.tiedup.remake.commands;
|
|
|
|
import com.mojang.brigadier.CommandDispatcher;
|
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
|
import com.mojang.brigadier.context.CommandContext;
|
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
import com.tiedup.remake.entities.*;
|
|
import com.tiedup.remake.entities.skins.EliteKidnapperSkinManager;
|
|
import com.tiedup.remake.items.ModItems;
|
|
import com.tiedup.remake.state.IBondageState;
|
|
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import com.tiedup.remake.v2.BodyRegionV2;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import net.minecraft.commands.CommandSourceStack;
|
|
import net.minecraft.commands.Commands;
|
|
import net.minecraft.commands.arguments.EntityArgument;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.server.level.ServerPlayer;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.MobSpawnType;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.phys.AABB;
|
|
|
|
/**
|
|
* NPC management commands.
|
|
*
|
|
* Commands:
|
|
* /npc spawn kidnapper [player] - Spawn a kidnapper at location
|
|
* /npc spawn elite <name> [player] - Spawn an elite kidnapper
|
|
* /npc spawn archer [player] - Spawn an archer kidnapper
|
|
* /npc spawn damsel [player] - Spawn a damsel NPC
|
|
* /npc kill [radius] - Kill all mod NPCs in radius
|
|
* /npc tie - Tie the nearest NPC
|
|
* /npc gag - Gag the nearest NPC
|
|
* /npc blindfold - Blindfold the nearest NPC
|
|
* /npc collar - Collar the nearest NPC
|
|
* /npc untie - Untie the nearest NPC (remove all)
|
|
* /npc state - Show state of nearest NPC
|
|
* /npc full - Apply full bondage to nearest NPC
|
|
*
|
|
* All commands require OP level 2.
|
|
*/
|
|
public class NPCCommand {
|
|
|
|
public static void register(
|
|
CommandDispatcher<CommandSourceStack> dispatcher
|
|
) {
|
|
dispatcher.register(createNPCCommand());
|
|
}
|
|
|
|
/**
|
|
* Create the NPC command builder (for use as subcommand of /tiedup).
|
|
* @return The command builder
|
|
*/
|
|
public static com.mojang.brigadier.builder.LiteralArgumentBuilder<
|
|
CommandSourceStack
|
|
> createNPCCommand() {
|
|
return Commands.literal("npc")
|
|
.requires(CommandHelper.REQUIRES_OP)
|
|
.then(
|
|
Commands.literal("spawn")
|
|
// /npc spawn kidnapper [player]
|
|
.then(
|
|
Commands.literal("kidnapper")
|
|
.executes(ctx -> spawnKidnapper(ctx, null))
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(ctx ->
|
|
spawnKidnapper(
|
|
ctx,
|
|
EntityArgument.getPlayer(ctx, "player")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
// /npc spawn elite <name> [player]
|
|
.then(
|
|
Commands.literal("elite").then(
|
|
Commands.argument("name", StringArgumentType.word())
|
|
.suggests((ctx, builder) -> {
|
|
for (KidnapperVariant v : EliteKidnapperSkinManager.CORE.getAllVariants()) {
|
|
builder.suggest(v.id());
|
|
}
|
|
return builder.buildFuture();
|
|
})
|
|
.executes(ctx -> spawnElite(ctx, null))
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(ctx ->
|
|
spawnElite(
|
|
ctx,
|
|
EntityArgument.getPlayer(
|
|
ctx,
|
|
"player"
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
// /npc spawn archer [player]
|
|
.then(
|
|
Commands.literal("archer")
|
|
.executes(ctx -> spawnArcher(ctx, null))
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(ctx ->
|
|
spawnArcher(
|
|
ctx,
|
|
EntityArgument.getPlayer(ctx, "player")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
// /npc spawn damsel [player]
|
|
.then(
|
|
Commands.literal("damsel")
|
|
.executes(ctx -> spawnDamsel(ctx, null))
|
|
.then(
|
|
Commands.argument(
|
|
"player",
|
|
EntityArgument.player()
|
|
).executes(ctx ->
|
|
spawnDamsel(
|
|
ctx,
|
|
EntityArgument.getPlayer(ctx, "player")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
// /npc kill <radius> - Kill all mod NPCs in radius
|
|
.then(
|
|
Commands.literal("kill")
|
|
.executes(ctx -> killNPCs(ctx, 10))
|
|
.then(
|
|
Commands.argument(
|
|
"radius",
|
|
com.mojang.brigadier.arguments.IntegerArgumentType.integer(
|
|
1,
|
|
100
|
|
)
|
|
).executes(ctx ->
|
|
killNPCs(
|
|
ctx,
|
|
com.mojang.brigadier.arguments.IntegerArgumentType.getInteger(
|
|
ctx,
|
|
"radius"
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
// /npc tie - Tie nearest NPC
|
|
.then(Commands.literal("tie").executes(NPCCommand::tieNPC))
|
|
// /npc gag - Gag nearest NPC
|
|
.then(Commands.literal("gag").executes(NPCCommand::gagNPC))
|
|
// /npc blindfold - Blindfold nearest NPC
|
|
.then(
|
|
Commands.literal("blindfold").executes(NPCCommand::blindfoldNPC)
|
|
)
|
|
// /npc collar - Collar nearest NPC
|
|
.then(Commands.literal("collar").executes(NPCCommand::collarNPC))
|
|
// /npc untie - Untie nearest NPC
|
|
.then(Commands.literal("untie").executes(NPCCommand::untieNPC))
|
|
// /npc state - Show NPC state
|
|
.then(Commands.literal("state").executes(NPCCommand::showNPCState))
|
|
// /npc full - Full bondage on nearest NPC
|
|
.then(
|
|
Commands.literal("full").executes(NPCCommand::fullBondageNPC)
|
|
);
|
|
}
|
|
|
|
private static int spawnKidnapper(
|
|
CommandContext<CommandSourceStack> context,
|
|
ServerPlayer targetPlayer
|
|
) throws CommandSyntaxException {
|
|
CommandSourceStack source = context.getSource();
|
|
ServerLevel level = source.getLevel();
|
|
|
|
// Get spawn location
|
|
double x, y, z;
|
|
if (targetPlayer != null) {
|
|
x = targetPlayer.getX();
|
|
y = targetPlayer.getY();
|
|
z = targetPlayer.getZ();
|
|
} else if (source.getEntity() instanceof ServerPlayer player) {
|
|
x = player.getX();
|
|
y = player.getY();
|
|
z = player.getZ();
|
|
} else {
|
|
source.sendFailure(
|
|
Component.literal("Must specify a player or be a player")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
// Spawn the kidnapper
|
|
EntityKidnapper kidnapper = ModEntities.KIDNAPPER.get().create(level);
|
|
if (kidnapper != null) {
|
|
kidnapper.moveTo(x, y, z, level.random.nextFloat() * 360F, 0.0F);
|
|
kidnapper.finalizeSpawn(
|
|
level,
|
|
level.getCurrentDifficultyAt(kidnapper.blockPosition()),
|
|
MobSpawnType.COMMAND,
|
|
null,
|
|
null
|
|
);
|
|
level.addFreshEntity(kidnapper);
|
|
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§aSpawned Kidnapper at " + formatPos(x, y, z)
|
|
),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
source.sendFailure(Component.literal("Failed to spawn Kidnapper"));
|
|
return 0;
|
|
}
|
|
|
|
private static int spawnElite(
|
|
CommandContext<CommandSourceStack> context,
|
|
ServerPlayer targetPlayer
|
|
) throws CommandSyntaxException {
|
|
CommandSourceStack source = context.getSource();
|
|
ServerLevel level = source.getLevel();
|
|
String name = StringArgumentType.getString(context, "name");
|
|
|
|
// Parse variant
|
|
KidnapperVariant variant = EliteKidnapperSkinManager.CORE.getVariant(
|
|
name
|
|
);
|
|
if (variant == null) {
|
|
source.sendFailure(
|
|
Component.literal(
|
|
"Unknown elite variant: " +
|
|
name +
|
|
". Available: suki, carol, athena, evelyn"
|
|
)
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
// Get spawn location
|
|
double x, y, z;
|
|
if (targetPlayer != null) {
|
|
x = targetPlayer.getX();
|
|
y = targetPlayer.getY();
|
|
z = targetPlayer.getZ();
|
|
} else if (source.getEntity() instanceof ServerPlayer player) {
|
|
x = player.getX();
|
|
y = player.getY();
|
|
z = player.getZ();
|
|
} else {
|
|
source.sendFailure(
|
|
Component.literal("Must specify a player or be a player")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
// Spawn the elite kidnapper
|
|
EntityKidnapperElite elite = ModEntities.KIDNAPPER_ELITE.get().create(
|
|
level
|
|
);
|
|
if (elite != null) {
|
|
elite.moveTo(x, y, z, level.random.nextFloat() * 360F, 0.0F);
|
|
elite.setKidnapperVariant(variant);
|
|
elite.finalizeSpawn(
|
|
level,
|
|
level.getCurrentDifficultyAt(elite.blockPosition()),
|
|
MobSpawnType.COMMAND,
|
|
null,
|
|
null
|
|
);
|
|
level.addFreshEntity(elite);
|
|
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§aSpawned Elite Kidnapper '" +
|
|
variant.defaultName() +
|
|
"' at " +
|
|
formatPos(x, y, z)
|
|
),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
source.sendFailure(
|
|
Component.literal("Failed to spawn Elite Kidnapper")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
private static int spawnArcher(
|
|
CommandContext<CommandSourceStack> context,
|
|
ServerPlayer targetPlayer
|
|
) throws CommandSyntaxException {
|
|
CommandSourceStack source = context.getSource();
|
|
ServerLevel level = source.getLevel();
|
|
|
|
// Get spawn location
|
|
double x, y, z;
|
|
if (targetPlayer != null) {
|
|
x = targetPlayer.getX();
|
|
y = targetPlayer.getY();
|
|
z = targetPlayer.getZ();
|
|
} else if (source.getEntity() instanceof ServerPlayer player) {
|
|
x = player.getX();
|
|
y = player.getY();
|
|
z = player.getZ();
|
|
} else {
|
|
source.sendFailure(
|
|
Component.literal("Must specify a player or be a player")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
// Spawn the archer
|
|
EntityKidnapperArcher archer =
|
|
ModEntities.KIDNAPPER_ARCHER.get().create(level);
|
|
if (archer != null) {
|
|
archer.moveTo(x, y, z, level.random.nextFloat() * 360F, 0.0F);
|
|
archer.finalizeSpawn(
|
|
level,
|
|
level.getCurrentDifficultyAt(archer.blockPosition()),
|
|
MobSpawnType.COMMAND,
|
|
null,
|
|
null
|
|
);
|
|
level.addFreshEntity(archer);
|
|
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§aSpawned Archer Kidnapper at " + formatPos(x, y, z)
|
|
),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
source.sendFailure(
|
|
Component.literal("Failed to spawn Archer Kidnapper")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
private static int spawnDamsel(
|
|
CommandContext<CommandSourceStack> context,
|
|
ServerPlayer targetPlayer
|
|
) throws CommandSyntaxException {
|
|
CommandSourceStack source = context.getSource();
|
|
ServerLevel level = source.getLevel();
|
|
|
|
// Get spawn location
|
|
double x, y, z;
|
|
if (targetPlayer != null) {
|
|
x = targetPlayer.getX();
|
|
y = targetPlayer.getY();
|
|
z = targetPlayer.getZ();
|
|
} else if (source.getEntity() instanceof ServerPlayer player) {
|
|
x = player.getX();
|
|
y = player.getY();
|
|
z = player.getZ();
|
|
} else {
|
|
source.sendFailure(
|
|
Component.literal("Must specify a player or be a player")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
// Spawn the damsel
|
|
EntityDamsel damsel = ModEntities.DAMSEL.get().create(level);
|
|
if (damsel != null) {
|
|
damsel.moveTo(x, y, z, level.random.nextFloat() * 360F, 0.0F);
|
|
damsel.finalizeSpawn(
|
|
level,
|
|
level.getCurrentDifficultyAt(damsel.blockPosition()),
|
|
MobSpawnType.COMMAND,
|
|
null,
|
|
null
|
|
);
|
|
level.addFreshEntity(damsel);
|
|
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§aSpawned Damsel at " + formatPos(x, y, z)
|
|
),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
source.sendFailure(Component.literal("Failed to spawn Damsel"));
|
|
return 0;
|
|
}
|
|
|
|
private static int killNPCs(
|
|
CommandContext<CommandSourceStack> context,
|
|
int radius
|
|
) throws CommandSyntaxException {
|
|
CommandSourceStack source = context.getSource();
|
|
|
|
Optional<ServerPlayer> playerOpt = CommandHelper.getPlayerOrFail(
|
|
source
|
|
);
|
|
if (playerOpt.isEmpty()) return 0;
|
|
ServerPlayer player = playerOpt.get();
|
|
|
|
ServerLevel level = player.serverLevel();
|
|
int killed = 0;
|
|
|
|
// Find and kill all mod NPCs in radius
|
|
var entities = level.getEntitiesOfClass(
|
|
net.minecraft.world.entity.LivingEntity.class,
|
|
player.getBoundingBox().inflate(radius),
|
|
e -> e instanceof com.tiedup.remake.entities.AbstractTiedUpNpc
|
|
);
|
|
|
|
for (var entity : entities) {
|
|
entity.discard();
|
|
killed++;
|
|
}
|
|
|
|
int finalKilled = killed;
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§aKilled " + finalKilled + " mod NPCs in radius " + radius
|
|
),
|
|
true
|
|
);
|
|
|
|
return killed;
|
|
}
|
|
|
|
private static String formatPos(double x, double y, double z) {
|
|
return String.format("(%.1f, %.1f, %.1f)", x, y, z);
|
|
}
|
|
|
|
// NPC Bondage Commands (from DamselTestCommand)
|
|
|
|
/**
|
|
* Find the nearest mod NPC (Damsel or Kidnapper) within 10 blocks.
|
|
*/
|
|
private static IBondageState findNearestNPC(
|
|
CommandContext<CommandSourceStack> context
|
|
) {
|
|
Entity source = context.getSource().getEntity();
|
|
if (source == null) return null;
|
|
|
|
AABB searchBox = source.getBoundingBox().inflate(10.0);
|
|
|
|
// Search for any IBondageState entity (EntityDamsel implements this)
|
|
List<EntityDamsel> npcs = source
|
|
.level()
|
|
.getEntitiesOfClass(EntityDamsel.class, searchBox);
|
|
|
|
if (npcs.isEmpty()) {
|
|
return null;
|
|
}
|
|
|
|
// Return closest NPC
|
|
return npcs
|
|
.stream()
|
|
.min((a, b) ->
|
|
Double.compare(a.distanceToSqr(source), b.distanceToSqr(source))
|
|
)
|
|
.orElse(null);
|
|
}
|
|
|
|
private static int tieNPC(CommandContext<CommandSourceStack> context) {
|
|
IBondageState npc = findNearestNPC(context);
|
|
if (npc == null) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(
|
|
Component.literal("No mod NPC found within 10 blocks")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
if (npc.isTiedUp()) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(Component.literal("NPC is already tied up"));
|
|
return 0;
|
|
}
|
|
|
|
npc.equip(
|
|
BodyRegionV2.ARMS,
|
|
DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "ropes"))
|
|
);
|
|
context
|
|
.getSource()
|
|
.sendSuccess(
|
|
() -> Component.literal("§aTied up " + npc.getKidnappedName()),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
private static int gagNPC(CommandContext<CommandSourceStack> context) {
|
|
IBondageState npc = findNearestNPC(context);
|
|
if (npc == null) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(
|
|
Component.literal("No mod NPC found within 10 blocks")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
if (npc.isGagged()) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(Component.literal("NPC is already gagged"));
|
|
return 0;
|
|
}
|
|
|
|
npc.equip(
|
|
BodyRegionV2.MOUTH,
|
|
DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "cloth_gag"))
|
|
);
|
|
context
|
|
.getSource()
|
|
.sendSuccess(
|
|
() -> Component.literal("§aGagged " + npc.getKidnappedName()),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
private static int blindfoldNPC(
|
|
CommandContext<CommandSourceStack> context
|
|
) {
|
|
IBondageState npc = findNearestNPC(context);
|
|
if (npc == null) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(
|
|
Component.literal("No mod NPC found within 10 blocks")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
if (npc.isBlindfolded()) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(Component.literal("NPC is already blindfolded"));
|
|
return 0;
|
|
}
|
|
|
|
npc.equip(
|
|
BodyRegionV2.EYES,
|
|
DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_blindfold"))
|
|
);
|
|
context
|
|
.getSource()
|
|
.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§aBlindfolded " + npc.getKidnappedName()
|
|
),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
private static int collarNPC(CommandContext<CommandSourceStack> context) {
|
|
IBondageState npc = findNearestNPC(context);
|
|
if (npc == null) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(
|
|
Component.literal("No mod NPC found within 10 blocks")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
if (npc.hasCollar()) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(Component.literal("NPC already has a collar"));
|
|
return 0;
|
|
}
|
|
|
|
npc.equip(
|
|
BodyRegionV2.NECK,
|
|
new ItemStack(ModItems.CLASSIC_COLLAR.get())
|
|
);
|
|
context
|
|
.getSource()
|
|
.sendSuccess(
|
|
() -> Component.literal("§aCollared " + npc.getKidnappedName()),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
private static int untieNPC(CommandContext<CommandSourceStack> context) {
|
|
IBondageState npc = findNearestNPC(context);
|
|
if (npc == null) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(
|
|
Component.literal("No mod NPC found within 10 blocks")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
npc.untie(true); // Drop items
|
|
context
|
|
.getSource()
|
|
.sendSuccess(
|
|
() -> Component.literal("§aUntied " + npc.getKidnappedName()),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
private static int fullBondageNPC(
|
|
CommandContext<CommandSourceStack> context
|
|
) {
|
|
IBondageState npc = findNearestNPC(context);
|
|
if (npc == null) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(
|
|
Component.literal("No mod NPC found within 10 blocks")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
// Apply full bondage using AbstractTiedUpNpc method
|
|
if (
|
|
npc instanceof
|
|
com.tiedup.remake.entities.AbstractTiedUpNpc npcEntity
|
|
) {
|
|
npcEntity.applyBondage(
|
|
DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "ropes")),
|
|
DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "cloth_gag")),
|
|
DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_blindfold")),
|
|
DataDrivenBondageItem.createStack(new ResourceLocation("tiedup", "classic_earplugs")),
|
|
new ItemStack(ModItems.CLASSIC_COLLAR.get()),
|
|
ItemStack.EMPTY // No clothes
|
|
);
|
|
}
|
|
|
|
context
|
|
.getSource()
|
|
.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§aFully restrained " + npc.getKidnappedName()
|
|
),
|
|
true
|
|
);
|
|
return 1;
|
|
}
|
|
|
|
private static int showNPCState(
|
|
CommandContext<CommandSourceStack> context
|
|
) {
|
|
IBondageState npc = findNearestNPC(context);
|
|
if (npc == null) {
|
|
context
|
|
.getSource()
|
|
.sendFailure(
|
|
Component.literal("No mod NPC found within 10 blocks")
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
CommandSourceStack source = context.getSource();
|
|
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§6=== NPC State: " + npc.getKidnappedName() + " ==="
|
|
),
|
|
false
|
|
);
|
|
|
|
if (npc instanceof EntityDamsel damsel) {
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal("§eVariant: §f" + damsel.getVariantId()),
|
|
false
|
|
);
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§eSlim Arms: " +
|
|
(damsel.hasSlimArms() ? "§aYes" : "§7No")
|
|
),
|
|
false
|
|
);
|
|
}
|
|
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§eTied Up: " + (npc.isTiedUp() ? "§aYes" : "§7No")
|
|
),
|
|
false
|
|
);
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§eGagged: " + (npc.isGagged() ? "§aYes" : "§7No")
|
|
),
|
|
false
|
|
);
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§eBlindfolded: " + (npc.isBlindfolded() ? "§aYes" : "§7No")
|
|
),
|
|
false
|
|
);
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§eHas Collar: " + (npc.hasCollar() ? "§aYes" : "§7No")
|
|
),
|
|
false
|
|
);
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§eHas Earplugs: " + (npc.hasEarplugs() ? "§aYes" : "§7No")
|
|
),
|
|
false
|
|
);
|
|
source.sendSuccess(
|
|
() ->
|
|
Component.literal(
|
|
"§eIs Captive: " + (npc.isCaptive() ? "§aYes" : "§7No")
|
|
),
|
|
false
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
}
|