Files
TiedUp-/src/main/java/com/tiedup/remake/entities/EntityRopeArrow.java
NotEvil 4e136cff96 centralize all ModConfig.SERVER reads through SettingsAccessor
No more direct ModConfig.SERVER access outside SettingsAccessor.
32 new accessor methods, 21 consumer files rerouted.
2026-04-16 13:16:05 +02:00

137 lines
4.6 KiB
Java

package com.tiedup.remake.entities;
import com.tiedup.remake.core.SettingsAccessor;
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 = SettingsAccessor.getRopeArrowBindChance();
}
// Roll for bind chance
int roll = this.random.nextInt(100) + 1;
if (roll <= bindChance) {
// Success! Bind the target
ItemStack ropeItem = com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(
new net.minecraft.resources.ResourceLocation("tiedup", "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());
}
}