Files
TiedUp-/src/main/java/com/tiedup/remake/entities/EntityRopeArrow.java
NotEvil a71093ba9c Remove internal phase comments and format code
Strip all Phase references, TODO/FUTURE roadmap notes, and internal
planning comments from the codebase. Run Prettier for consistent
formatting across all Java files.
2026-04-12 01:25:55 +02:00

139 lines
4.6 KiB
Java

package com.tiedup.remake.entities;
import com.tiedup.remake.core.ModConfig;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.ModItems;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.EntityHitResult;
/**
* Rope Arrow Entity - Arrow that binds targets on hit.
*
*
* Behavior:
* - When hitting an entity, has a chance to bind them
* - Default: 50% chance
* - From Archer Kidnapper: 10% base + 10% per previous hit on same target
* - Uses rope restraint on target
* - Target must be IBondageState (Player, Damsel, Kidnapper)
*/
public class EntityRopeArrow extends AbstractArrow {
public EntityRopeArrow(
EntityType<? extends EntityRopeArrow> type,
Level level
) {
super(type, level);
}
public EntityRopeArrow(Level level, LivingEntity shooter) {
super(ModEntities.ROPE_ARROW.get(), shooter, level);
}
public EntityRopeArrow(Level level, double x, double y, double z) {
super(ModEntities.ROPE_ARROW.get(), x, y, z, level);
}
/**
* Called when the arrow hits an entity.
* Attempts to bind the target with a chance based on shooter type.
*/
@Override
protected void onHitEntity(EntityHitResult result) {
// Don't call super - we don't want normal arrow damage
if (this.level().isClientSide) {
return;
}
if (result.getEntity() instanceof LivingEntity target) {
// Check if target can be kidnapped
IBondageState targetState = KidnappedHelper.getKidnappedState(
target
);
if (targetState == null) {
TiedUpMod.LOGGER.debug(
"[EntityRopeArrow] Target {} cannot be bound (not IBondageState)",
target.getName().getString()
);
// Remove arrow
this.discard();
return;
}
// Already tied?
if (targetState.isTiedUp()) {
TiedUpMod.LOGGER.debug(
"[EntityRopeArrow] Target {} is already tied",
target.getName().getString()
);
this.discard();
return;
}
// Determine bind chance based on shooter type
int bindChance;
EntityKidnapperArcher archerShooter = null;
if (this.getOwner() instanceof EntityKidnapperArcher archer) {
// Archer kidnapper: cumulative chance system
archerShooter = archer;
bindChance = archer.getBindChanceForTarget(target.getUUID());
} else {
// Other shooters: default 50% chance
bindChance = ModConfig.SERVER.ropeArrowBindChance.get();
}
// Roll for bind chance
int roll = this.random.nextInt(100) + 1;
if (roll <= bindChance) {
// Success! Bind the target
ItemStack ropeItem = new ItemStack(
ModItems.getBind(
com.tiedup.remake.items.base.BindVariant.ROPES
)
);
targetState.equip(BodyRegionV2.ARMS, ropeItem);
TiedUpMod.LOGGER.info(
"[EntityRopeArrow] Successfully bound {} (roll: {} <= {}%)",
target.getName().getString(),
roll,
bindChance
);
// Clear hit counts for this target if shot by archer
if (archerShooter != null) {
archerShooter.clearHitsForTarget(target.getUUID());
}
} else {
TiedUpMod.LOGGER.debug(
"[EntityRopeArrow] Failed to bind {} (roll: {} > {}%)",
target.getName().getString(),
roll,
bindChance
);
// Record hit for archer's cumulative chance
if (archerShooter != null) {
archerShooter.recordHitOnTarget(target.getUUID());
}
}
}
// Remove the arrow after hit
this.discard();
}
@Override
protected ItemStack getPickupItem() {
return new ItemStack(ModItems.ROPE_ARROW.get());
}
}