No more direct ModConfig.SERVER access outside SettingsAccessor. 32 new accessor methods, 21 consumer files rerouted.
137 lines
4.6 KiB
Java
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());
|
|
}
|
|
}
|