126 lines
5.8 KiB
Java
126 lines
5.8 KiB
Java
package net.minecraft.world.entity.ai.behavior;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.function.Function;
|
|
import java.util.function.ToDoubleFunction;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Position;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.valueproviders.UniformInt;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.effect.MobEffects;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.ai.Brain;
|
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
|
import net.minecraft.world.entity.ai.memory.MemoryStatus;
|
|
import net.minecraft.world.entity.ai.memory.WalkTarget;
|
|
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
|
|
import net.minecraft.world.entity.animal.goat.Goat;
|
|
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
|
import net.minecraft.world.phys.Vec3;
|
|
|
|
public class RamTarget extends Behavior<Goat> {
|
|
public static final int TIME_OUT_DURATION = 200;
|
|
public static final float RAM_SPEED_FORCE_FACTOR = 1.65F;
|
|
private final Function<Goat, UniformInt> getTimeBetweenRams;
|
|
private final TargetingConditions ramTargeting;
|
|
private final float speed;
|
|
private final ToDoubleFunction<Goat> getKnockbackForce;
|
|
private Vec3 ramDirection;
|
|
private final Function<Goat, SoundEvent> getImpactSound;
|
|
private final Function<Goat, SoundEvent> getHornBreakSound;
|
|
|
|
public RamTarget(
|
|
Function<Goat, UniformInt> getTimeBetweenRams,
|
|
TargetingConditions ramTargeting,
|
|
float speed,
|
|
ToDoubleFunction<Goat> getKnockbackForce,
|
|
Function<Goat, SoundEvent> getImpactSound,
|
|
Function<Goat, SoundEvent> getHornBreakSound
|
|
) {
|
|
super(ImmutableMap.of(MemoryModuleType.RAM_COOLDOWN_TICKS, MemoryStatus.VALUE_ABSENT, MemoryModuleType.RAM_TARGET, MemoryStatus.VALUE_PRESENT), 200);
|
|
this.getTimeBetweenRams = getTimeBetweenRams;
|
|
this.ramTargeting = ramTargeting;
|
|
this.speed = speed;
|
|
this.getKnockbackForce = getKnockbackForce;
|
|
this.getImpactSound = getImpactSound;
|
|
this.getHornBreakSound = getHornBreakSound;
|
|
this.ramDirection = Vec3.ZERO;
|
|
}
|
|
|
|
protected boolean checkExtraStartConditions(ServerLevel serverLevel, Goat goat) {
|
|
return goat.getBrain().hasMemoryValue(MemoryModuleType.RAM_TARGET);
|
|
}
|
|
|
|
protected boolean canStillUse(ServerLevel serverLevel, Goat goat, long l) {
|
|
return goat.getBrain().hasMemoryValue(MemoryModuleType.RAM_TARGET);
|
|
}
|
|
|
|
protected void start(ServerLevel serverLevel, Goat goat, long l) {
|
|
BlockPos blockPos = goat.blockPosition();
|
|
Brain<?> brain = goat.getBrain();
|
|
Vec3 vec3 = (Vec3)brain.getMemory(MemoryModuleType.RAM_TARGET).get();
|
|
this.ramDirection = new Vec3(blockPos.getX() - vec3.x(), 0.0, blockPos.getZ() - vec3.z()).normalize();
|
|
brain.setMemory(MemoryModuleType.WALK_TARGET, new WalkTarget(vec3, this.speed, 0));
|
|
}
|
|
|
|
protected void tick(ServerLevel serverLevel, Goat goat, long l) {
|
|
List<LivingEntity> list = serverLevel.getNearbyEntities(LivingEntity.class, this.ramTargeting, goat, goat.getBoundingBox());
|
|
Brain<?> brain = goat.getBrain();
|
|
if (!list.isEmpty()) {
|
|
LivingEntity livingEntity = (LivingEntity)list.get(0);
|
|
DamageSource damageSource = serverLevel.damageSources().noAggroMobAttack(goat);
|
|
float f = (float)goat.getAttributeValue(Attributes.ATTACK_DAMAGE);
|
|
if (livingEntity.hurtServer(serverLevel, damageSource, f)) {
|
|
EnchantmentHelper.doPostAttackEffects(serverLevel, livingEntity, damageSource);
|
|
}
|
|
|
|
int i = goat.hasEffect(MobEffects.SPEED) ? goat.getEffect(MobEffects.SPEED).getAmplifier() + 1 : 0;
|
|
int j = goat.hasEffect(MobEffects.SLOWNESS) ? goat.getEffect(MobEffects.SLOWNESS).getAmplifier() + 1 : 0;
|
|
float g = 0.25F * (i - j);
|
|
float h = Mth.clamp(goat.getSpeed() * 1.65F, 0.2F, 3.0F) + g;
|
|
DamageSource damageSource2 = serverLevel.damageSources().mobAttack(goat);
|
|
float k = livingEntity.applyItemBlocking(serverLevel, damageSource2, f);
|
|
float m = k > 0.0F ? 0.5F : 1.0F;
|
|
livingEntity.knockback(m * h * this.getKnockbackForce.applyAsDouble(goat), this.ramDirection.x(), this.ramDirection.z());
|
|
this.finishRam(serverLevel, goat);
|
|
serverLevel.playSound(null, goat, (SoundEvent)this.getImpactSound.apply(goat), SoundSource.NEUTRAL, 1.0F, 1.0F);
|
|
} else if (this.hasRammedHornBreakingBlock(serverLevel, goat)) {
|
|
serverLevel.playSound(null, goat, (SoundEvent)this.getImpactSound.apply(goat), SoundSource.NEUTRAL, 1.0F, 1.0F);
|
|
boolean bl = goat.dropHorn();
|
|
if (bl) {
|
|
serverLevel.playSound(null, goat, (SoundEvent)this.getHornBreakSound.apply(goat), SoundSource.NEUTRAL, 1.0F, 1.0F);
|
|
}
|
|
|
|
this.finishRam(serverLevel, goat);
|
|
} else {
|
|
Optional<WalkTarget> optional = brain.getMemory(MemoryModuleType.WALK_TARGET);
|
|
Optional<Vec3> optional2 = brain.getMemory(MemoryModuleType.RAM_TARGET);
|
|
boolean bl2 = optional.isEmpty()
|
|
|| optional2.isEmpty()
|
|
|| ((WalkTarget)optional.get()).getTarget().currentPosition().closerThan((Position)optional2.get(), 0.25);
|
|
if (bl2) {
|
|
this.finishRam(serverLevel, goat);
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean hasRammedHornBreakingBlock(ServerLevel level, Goat owner) {
|
|
Vec3 vec3 = owner.getDeltaMovement().multiply(1.0, 0.0, 1.0).normalize();
|
|
BlockPos blockPos = BlockPos.containing(owner.position().add(vec3));
|
|
return level.getBlockState(blockPos).is(BlockTags.SNAPS_GOAT_HORN) || level.getBlockState(blockPos.above()).is(BlockTags.SNAPS_GOAT_HORN);
|
|
}
|
|
|
|
protected void finishRam(ServerLevel level, Goat owner) {
|
|
level.broadcastEntityEvent(owner, (byte)59);
|
|
owner.getBrain().setMemory(MemoryModuleType.RAM_COOLDOWN_TICKS, ((UniformInt)this.getTimeBetweenRams.apply(owner)).sample(level.random));
|
|
owner.getBrain().eraseMemory(MemoryModuleType.RAM_TARGET);
|
|
}
|
|
}
|