545 lines
21 KiB
Java
545 lines
21 KiB
Java
package com.cursedcauldron.wildbackport.common.entities;
|
|
|
|
import com.cursedcauldron.wildbackport.WildBackport;
|
|
import com.cursedcauldron.wildbackport.client.animation.api.AnimationState;
|
|
import com.cursedcauldron.wildbackport.client.registry.WBSoundEvents;
|
|
import com.cursedcauldron.wildbackport.common.entities.access.api.Poses;
|
|
import com.cursedcauldron.wildbackport.common.entities.brain.WardenBrain;
|
|
import com.cursedcauldron.wildbackport.common.entities.brain.warden.SonicBoom;
|
|
import com.cursedcauldron.wildbackport.common.entities.warden.Angriness;
|
|
import com.cursedcauldron.wildbackport.common.entities.warden.MobPositionSource;
|
|
import com.cursedcauldron.wildbackport.common.entities.warden.VibrationHandler;
|
|
import com.cursedcauldron.wildbackport.common.entities.warden.WardenAngerManager;
|
|
import com.cursedcauldron.wildbackport.common.registry.WBMobEffects;
|
|
import com.cursedcauldron.wildbackport.common.registry.entity.WBEntityTypes;
|
|
import com.cursedcauldron.wildbackport.common.registry.entity.WBMemoryModules;
|
|
import com.cursedcauldron.wildbackport.common.tag.WBGameEventTags;
|
|
import com.cursedcauldron.wildbackport.common.utils.MobUtils;
|
|
import com.mojang.serialization.Dynamic;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.particles.BlockParticleOption;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.NbtOps;
|
|
import net.minecraft.network.protocol.Packet;
|
|
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
|
|
import net.minecraft.network.protocol.game.DebugPackets;
|
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
|
import net.minecraft.network.syncher.SynchedEntityData;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.tags.TagKey;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.Unit;
|
|
import net.minecraft.world.DifficultyInstance;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.damagesource.IndirectEntityDamageSource;
|
|
import net.minecraft.world.effect.MobEffectInstance;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityDimensions;
|
|
import net.minecraft.world.entity.EntitySelector;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.MobSpawnType;
|
|
import net.minecraft.world.entity.Pose;
|
|
import net.minecraft.world.entity.SpawnGroupData;
|
|
import net.minecraft.world.entity.ai.Brain;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
|
import net.minecraft.world.entity.monster.Monster;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.LevelReader;
|
|
import net.minecraft.world.level.ServerLevelAccessor;
|
|
import net.minecraft.world.level.block.RenderShape;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.gameevent.GameEvent;
|
|
import net.minecraft.world.level.gameevent.GameEventListener;
|
|
import net.minecraft.world.level.gameevent.GameEventListenerRegistrar;
|
|
import net.minecraft.world.level.pathfinder.BlockPathTypes;
|
|
import net.minecraft.world.phys.Vec3;
|
|
|
|
import javax.annotation.Nullable;
|
|
import java.util.Collections;
|
|
import java.util.Optional;
|
|
import java.util.Random;
|
|
|
|
//<>
|
|
|
|
public class Warden extends Monster implements VibrationHandler.VibrationConfig {
|
|
public static final byte PLAY_ATTACK_SOUND = 4;
|
|
public static final byte EARS_TWITCH = 61;
|
|
public static final byte SONIC_BOOM = 62;
|
|
private static final EntityDataAccessor<Integer> ANGER = SynchedEntityData.defineId(Warden.class, EntityDataSerializers.INT);
|
|
private int tendrilPitchEnd;
|
|
private int tendrilPitchStart;
|
|
private int heartPitchEnd;
|
|
private int heartPitchStart;
|
|
public AnimationState roaringAnimationState = new AnimationState();
|
|
public AnimationState sniffingAnimationState = new AnimationState();
|
|
public AnimationState emergingAnimationState = new AnimationState();
|
|
public AnimationState diggingAnimationState = new AnimationState();
|
|
public AnimationState attackingAnimationState = new AnimationState();
|
|
public AnimationState sonicBoomAnimationState = new AnimationState();
|
|
private final GameEventListenerRegistrar gameEventHandler;
|
|
private final VibrationHandler listener;
|
|
private WardenAngerManager angerManager = new WardenAngerManager(this::isValidTarget, Collections.emptyList());
|
|
|
|
public Warden(EntityType<? extends Monster> type, Level level) {
|
|
super(type, level);
|
|
this.listener = new VibrationHandler(new MobPositionSource(this, this.getEyeHeight()), 16, this);
|
|
this.gameEventHandler = new GameEventListenerRegistrar(this.listener);
|
|
this.xpReward = 5;
|
|
this.getNavigation().setCanFloat(true);
|
|
this.setPathfindingMalus(BlockPathTypes.UNPASSABLE_RAIL, 0.0F);
|
|
this.setPathfindingMalus(BlockPathTypes.DAMAGE_OTHER, 8.0F);
|
|
this.setPathfindingMalus(BlockPathTypes.POWDER_SNOW, 8.0F);
|
|
this.setPathfindingMalus(BlockPathTypes.LAVA, 8.0F);
|
|
this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, 0.0F);
|
|
this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 0.0F);
|
|
}
|
|
|
|
@Override
|
|
public Packet<?> getAddEntityPacket() {
|
|
return new ClientboundAddEntityPacket(this, this.hasPose(Poses.EMERGING.get()) ? 1 : 0);
|
|
}
|
|
|
|
@Override
|
|
public void recreateFromPacket(ClientboundAddEntityPacket packet) {
|
|
super.recreateFromPacket(packet);
|
|
if (packet.getData() == 1) this.setPose(Poses.EMERGING.get());
|
|
}
|
|
|
|
@Override
|
|
public boolean checkSpawnObstruction(LevelReader reader) {
|
|
return super.checkSpawnObstruction(reader) && reader.noCollision(this, this.getType().getDimensions().makeBoundingBox(this.position()));
|
|
}
|
|
|
|
@Override
|
|
public float getWalkTargetValue(BlockPos pos, LevelReader reader) {
|
|
return 0.0F;
|
|
}
|
|
|
|
@Override
|
|
public boolean isInvulnerableTo(DamageSource source) {
|
|
return this.isDiggingOrEmerging() && !source.isBypassInvul() || super.isInvulnerableTo(source);
|
|
}
|
|
|
|
private boolean isDiggingOrEmerging() {
|
|
return this.hasPose(Poses.DIGGING.get()) || this.hasPose(Poses.EMERGING.get());
|
|
}
|
|
|
|
@Override
|
|
protected boolean canRide(Entity entity) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
protected float nextStep() {
|
|
return this.moveDist + 0.55F;
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 500.0D).add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.KNOCKBACK_RESISTANCE, 1.0D).add(Attributes.ATTACK_KNOCKBACK, 1.5D).add(Attributes.ATTACK_DAMAGE, 30.0D);
|
|
}
|
|
|
|
@Override
|
|
public boolean occludesVibrations() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected float getSoundVolume() {
|
|
return 4.0F;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
protected SoundEvent getAmbientSound() {
|
|
return !this.hasPose(Poses.ROARING.get()) && !this.isDiggingOrEmerging() ? this.getAngriness().getSound() : null;
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getHurtSound(DamageSource source) {
|
|
return WBSoundEvents.WARDEN_HURT;
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getDeathSound() {
|
|
return WBSoundEvents.WARDEN_DEATH;
|
|
}
|
|
|
|
@Override
|
|
protected void playStepSound(BlockPos pos, BlockState state) {
|
|
this.playSound(WBSoundEvents.WARDEN_STEP, 10.0F, 1.0F);
|
|
}
|
|
|
|
@Override
|
|
public boolean doHurtTarget(Entity entity) {
|
|
this.level.broadcastEntityEvent(this, (byte)4);
|
|
this.playSound(WBSoundEvents.WARDEN_ATTACK_IMPACT, 10.0F, this.getVoicePitch());
|
|
SonicBoom.setCooldown(this, 40);
|
|
return super.doHurtTarget(entity);
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData() {
|
|
super.defineSynchedData();
|
|
this.entityData.define(ANGER, 0);
|
|
}
|
|
|
|
public int getAnger() {
|
|
return this.entityData.get(ANGER);
|
|
}
|
|
|
|
private void updateAnger() {
|
|
this.entityData.set(ANGER, this.getPrimeSuspectAnger());
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
if (this.level instanceof ServerLevel server) {
|
|
this.listener.tick(server);
|
|
if (this.isPersistenceRequired() || this.requiresCustomPersistence()) {
|
|
WardenBrain.resetDigCooldown(this);
|
|
}
|
|
}
|
|
|
|
super.tick();
|
|
if (this.level.isClientSide()) {
|
|
if (this.tickCount % this.getHeartRate() == 0) {
|
|
this.heartPitchEnd = 10;
|
|
if (!this.isSilent()) {
|
|
this.level.playLocalSound(this.getX(), this.getY(), this.getZ(), WBSoundEvents.WARDEN_HEARTBEAT, this.getSoundSource(), 5.0F, this.getVoicePitch(), false);
|
|
}
|
|
}
|
|
|
|
this.tendrilPitchStart = this.tendrilPitchEnd;
|
|
if (this.tendrilPitchEnd > 0) {
|
|
--this.tendrilPitchEnd;
|
|
}
|
|
|
|
this.heartPitchStart = this.heartPitchEnd;
|
|
if (this.heartPitchEnd > 0) {
|
|
--this.heartPitchEnd;
|
|
}
|
|
|
|
if (this.hasPose(Poses.EMERGING.get())) {
|
|
this.addDigParticles(this.emergingAnimationState);
|
|
}
|
|
|
|
if (this.hasPose(Poses.DIGGING.get())) {
|
|
this.addDigParticles(this.diggingAnimationState);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void customServerAiStep() {
|
|
ServerLevel level = (ServerLevel)this.level;
|
|
level.getProfiler().push("wardenBrain");
|
|
this.getBrain().tick(level, this);
|
|
this.level.getProfiler().pop();
|
|
super.customServerAiStep();
|
|
if ((this.tickCount + this.getId()) % 120 == 0) {
|
|
addDarknessToClosePlayers(level, this.position(), this, 20);
|
|
}
|
|
|
|
if (this.tickCount % 20 == 0) {
|
|
this.angerManager.tick(level, this::isValidTarget);
|
|
this.updateAnger();
|
|
}
|
|
|
|
WardenBrain.updateActivities(this);
|
|
}
|
|
|
|
@Override
|
|
public void handleEntityEvent(byte status) {
|
|
if (status == 4) {
|
|
this.roaringAnimationState.stop();
|
|
this.attackingAnimationState.start(this.tickCount);
|
|
} else if (status == 61) {
|
|
this.tendrilPitchEnd = 10;
|
|
} else if (status == 62) {
|
|
this.sonicBoomAnimationState.start(this.tickCount);
|
|
} else {
|
|
super.handleEntityEvent(status);
|
|
}
|
|
}
|
|
|
|
private int getHeartRate() {
|
|
return 40 - Mth.floor(Mth.clamp((float)this.getAnger() / (float)Angriness.ANGRY.getThreshold(), 0.0F, 1.0F) * 30.0F);
|
|
}
|
|
|
|
public float getTendrilPitch(float tickDelta) {
|
|
return Mth.lerp(tickDelta, (float)this.tendrilPitchStart, (float)this.tendrilPitchEnd) / 10.0F;
|
|
}
|
|
|
|
public float getHeartPitch(float tickDelta) {
|
|
return Mth.lerp(tickDelta, (float)this.heartPitchStart, (float)this.heartPitchEnd) / 10.0F;
|
|
}
|
|
|
|
private void addDigParticles(AnimationState animationState) {
|
|
if ((float)animationState.runningTime() < 4500.0F) {
|
|
Random random = this.getRandom();
|
|
BlockState state = this.getBlockStateOn();
|
|
if (state.getRenderShape() != RenderShape.INVISIBLE) {
|
|
for (int i = 0; i < 30; i++) {
|
|
double x = this.getX() + (double)Mth.randomBetween(random, -0.7F, 0.7F);
|
|
double y = this.getY();
|
|
double z = this.getZ() + (double)Mth.randomBetween(random, -0.7F, 0.7F);
|
|
this.level.addParticle(new BlockParticleOption(ParticleTypes.BLOCK, state), x, y, z, 0.0D, 0.0D, 0.0D);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSyncedDataUpdated(EntityDataAccessor<?> data) {
|
|
if (DATA_POSE.equals(data)) {
|
|
if (this.hasPose(Poses.EMERGING.get())) {
|
|
this.emergingAnimationState.start(this.tickCount);
|
|
} else if (this.hasPose(Poses.DIGGING.get())) {
|
|
this.diggingAnimationState.start(this.tickCount);
|
|
} else if (this.hasPose(Poses.ROARING.get())) {
|
|
this.roaringAnimationState.start(this.tickCount);
|
|
} else if (this.hasPose(Poses.SNIFFING.get())) {
|
|
this.sniffingAnimationState.start(this.tickCount);
|
|
}
|
|
}
|
|
|
|
super.onSyncedDataUpdated(data);
|
|
}
|
|
|
|
public boolean hasPose(Pose pose) {
|
|
return this.getPose() == pose;
|
|
}
|
|
|
|
@Override
|
|
public boolean ignoreExplosion() {
|
|
return this.isDiggingOrEmerging();
|
|
}
|
|
|
|
@Override
|
|
protected Brain<?> makeBrain(Dynamic<?> dynamic) {
|
|
return WardenBrain.makeBrain(this, dynamic);
|
|
}
|
|
|
|
@Override @SuppressWarnings("unchecked")
|
|
public Brain<Warden> getBrain() {
|
|
return (Brain<Warden>)super.getBrain();
|
|
}
|
|
|
|
@Override
|
|
protected void sendDebugPackets() {
|
|
super.sendDebugPackets();
|
|
DebugPackets.sendEntityBrain(this);
|
|
}
|
|
|
|
@Override
|
|
public TagKey<GameEvent> getListenableEvents() {
|
|
return WBGameEventTags.WARDEN_CAN_LISTEN;
|
|
}
|
|
|
|
@Override
|
|
public boolean canTriggerAvoidVibration() {
|
|
return true;
|
|
}
|
|
|
|
public boolean isValidTarget(@Nullable Entity entity) {
|
|
if (entity instanceof LivingEntity living) {
|
|
return this.level == entity.level && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity) && !this.isAlliedTo(entity) && living.getType() != EntityType.ARMOR_STAND && living.getType() != WBEntityTypes.WARDEN.get() && !living.isInvulnerable() && !living.isDeadOrDying() && this.level.getWorldBorder().isWithinBounds(living.getBoundingBox());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static void addDarknessToClosePlayers(ServerLevel world, Vec3 pos, @Nullable Entity entity, int range) {
|
|
MobEffectInstance instance = new MobEffectInstance(WBMobEffects.DARKNESS.get(), 260, 0, false, false);
|
|
MobUtils.addEffectToPlayersWithinDistance(world, entity, pos, range, instance, 200);
|
|
}
|
|
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag tag) {
|
|
super.addAdditionalSaveData(tag);
|
|
WardenAngerManager.codec(this::isValidTarget).encodeStart(NbtOps.INSTANCE, this.angerManager).resultOrPartial(WildBackport.LOGGER::error).ifPresent(manager -> tag.put("anger", manager));
|
|
|
|
}
|
|
|
|
@Override
|
|
public void readAdditionalSaveData(CompoundTag tag) {
|
|
super.readAdditionalSaveData(tag);
|
|
if (tag.contains("anger")) {
|
|
WardenAngerManager.codec(this::isValidTarget).parse(new Dynamic<>(NbtOps.INSTANCE, tag.get("anger"))).resultOrPartial(WildBackport.LOGGER::error).ifPresent(manager -> this.angerManager = manager);
|
|
this.updateAnger();
|
|
}
|
|
}
|
|
|
|
private void playListeningSound() {
|
|
if (!this.hasPose(Poses.ROARING.get())) this.playSound(this.getAngriness().getListeningSound(), 10.0F, this.getVoicePitch());
|
|
}
|
|
|
|
public Angriness getAngriness() {
|
|
return Angriness.getForAnger(this.getPrimeSuspectAnger());
|
|
}
|
|
|
|
public int getPrimeSuspectAnger() {
|
|
return this.angerManager.getAngerFor(this.getTarget());
|
|
}
|
|
|
|
public void removeSuspect(Entity entity) {
|
|
this.angerManager.removeSuspect(entity);
|
|
}
|
|
|
|
public void increaseAngerAt(Entity entity) {
|
|
this.increaseAngerAt(entity, 35, true);
|
|
}
|
|
|
|
public void increaseAngerAt(Entity entity, int amount, boolean listening) {
|
|
if (!this.isNoAi() && this.isValidTarget(entity)) {
|
|
WardenBrain.resetDigCooldown(this);
|
|
boolean targetNotPlayer = !(this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null) instanceof Player);
|
|
int anger = this.angerManager.increaseAngerAt(entity, amount);
|
|
if (entity instanceof Player && targetNotPlayer && Angriness.getForAnger(anger).isAngry()) {
|
|
this.getBrain().eraseMemory(MemoryModuleType.ATTACK_TARGET);
|
|
}
|
|
|
|
if (listening) this.playListeningSound();
|
|
}
|
|
}
|
|
|
|
public Optional<LivingEntity> getPrimeSuspect() {
|
|
return this.getAngriness().isAngry() ? this.angerManager.getPrimeSuspect() : Optional.empty();
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public LivingEntity getTarget() {
|
|
return this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null);
|
|
}
|
|
|
|
@Override
|
|
public boolean removeWhenFarAway(double sqrDist) {
|
|
return false;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance instance, MobSpawnType spawn, @Nullable SpawnGroupData data, @Nullable CompoundTag tag) {
|
|
this.getBrain().setMemoryWithExpiry(WBMemoryModules.DIG_COOLDOWN.get(), Unit.INSTANCE, 1200L);
|
|
if (spawn == MobSpawnType.TRIGGERED) {
|
|
this.setPose(Poses.EMERGING.get());
|
|
this.getBrain().setMemoryWithExpiry(WBMemoryModules.IS_EMERGING.get(), Unit.INSTANCE, WardenBrain.EMERGE_DURATION);
|
|
this.playSound(WBSoundEvents.WARDEN_AGITATED, 5.0F, 1.0F);
|
|
}
|
|
|
|
return super.finalizeSpawn(level, instance, spawn, data, tag);
|
|
}
|
|
|
|
@Override
|
|
public boolean hurt(DamageSource source, float amount) {
|
|
boolean hurt = super.hurt(source, amount);
|
|
if (!this.level.isClientSide && !this.isNoAi() && !this.isDiggingOrEmerging()) {
|
|
Entity entity = source.getEntity();
|
|
this.increaseAngerAt(entity, Angriness.ANGRY.getThreshold() + 20, false);
|
|
if (this.brain.getMemory(MemoryModuleType.ATTACK_TARGET).isEmpty() && entity instanceof LivingEntity living) {
|
|
if (!(source instanceof IndirectEntityDamageSource) || this.closerThan(living, 5.0D)) {
|
|
this.updateAttackTarget(living);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hurt;
|
|
}
|
|
|
|
public void updateAttackTarget(LivingEntity entity) {
|
|
this.getBrain().eraseMemory(WBMemoryModules.ROAR_TARGET.get());
|
|
this.getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, entity);
|
|
this.getBrain().eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE);
|
|
SonicBoom.setCooldown(this, 200);
|
|
}
|
|
|
|
@Override
|
|
public EntityDimensions getDimensions(Pose pose) {
|
|
EntityDimensions dimensions = super.getDimensions(pose);
|
|
return this.isDiggingOrEmerging() ? EntityDimensions.fixed(dimensions.width, 1.0F) : dimensions;
|
|
}
|
|
|
|
@Override
|
|
public boolean isPushable() {
|
|
return !this.isDiggingOrEmerging() && super.isPushable();
|
|
}
|
|
|
|
@Override
|
|
protected void doPush(Entity entity) {
|
|
if (!this.isNoAi() && !this.getBrain().hasMemoryValue(WBMemoryModules.TOUCH_COOLDOWN.get())) {
|
|
this.getBrain().setMemoryWithExpiry(WBMemoryModules.TOUCH_COOLDOWN.get(), Unit.INSTANCE, 20L);
|
|
this.increaseAngerAt(entity);
|
|
WardenBrain.lookAtDisturbance(this, entity.blockPosition());
|
|
}
|
|
|
|
super.doPush(entity);
|
|
}
|
|
|
|
@Override
|
|
public boolean shouldListen(ServerLevel level, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable Entity entity) {
|
|
if (!this.isNoAi() && !this.isDeadOrDying() && !this.getBrain().hasMemoryValue(WBMemoryModules.VIBRATION_COOLDOWN.get()) && !this.isDiggingOrEmerging() && level.getWorldBorder().isWithinBounds(pos) && !this.isRemoved() && this.level == level) {
|
|
if (entity instanceof LivingEntity living) {
|
|
return this.isValidTarget(living);
|
|
}
|
|
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSignalReceive(ServerLevel level, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable Entity entity, @Nullable Entity source, float distance) {
|
|
if (!this.isDeadOrDying()) {
|
|
this.brain.setMemoryWithExpiry(WBMemoryModules.VIBRATION_COOLDOWN.get(), Unit.INSTANCE, 40L);
|
|
level.broadcastEntityEvent(this, (byte)61);
|
|
this.playSound(WBSoundEvents.WARDEN_TENDRIL_CLICKS, 5.0F, this.getVoicePitch());
|
|
BlockPos position = pos;
|
|
if (source != null) {
|
|
if (this.closerThan(source, 30.0D)) {
|
|
if (this.getBrain().hasMemoryValue(WBMemoryModules.RECENT_PROJECTILE.get())) {
|
|
if (this.isValidTarget(source)) {
|
|
position = source.blockPosition();
|
|
}
|
|
|
|
this.increaseAngerAt(source);
|
|
} else {
|
|
this.increaseAngerAt(source, 10, true);
|
|
}
|
|
}
|
|
|
|
this.getBrain().setMemoryWithExpiry(WBMemoryModules.RECENT_PROJECTILE.get(), Unit.INSTANCE, 100L);
|
|
} else {
|
|
this.increaseAngerAt(entity);
|
|
}
|
|
|
|
if (!this.getAngriness().isAngry()) {
|
|
Optional<LivingEntity> primeSuspect = this.angerManager.getPrimeSuspect();
|
|
if (source != null || primeSuspect.isEmpty() || primeSuspect.get() == entity) {
|
|
WardenBrain.lookAtDisturbance(this, position);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public GameEventListenerRegistrar getGameEventListenerRegistrar() {
|
|
return this.gameEventHandler;
|
|
}
|
|
|
|
public boolean closerThan(Entity entity, double xzRange, double yRange) {
|
|
double x = entity.getX() - this.getX();
|
|
double y = entity.getY() - this.getY();
|
|
double z = entity.getZ() - this.getZ();
|
|
return Mth.lengthSquared(x, z) < Mth.square(xzRange) && Mth.square(y) < Mth.square(yRange);
|
|
}
|
|
} |