312 lines
12 KiB
Java
312 lines
12 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* org.jspecify.annotations.Nullable
|
|
*/
|
|
package net.minecraft.world.entity.animal;
|
|
|
|
import java.util.Objects;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.particles.ParticleOptions;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.tags.FluidTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.DifficultyInstance;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.effect.MobEffects;
|
|
import net.minecraft.world.entity.AgeableMob;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntitySpawnReason;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.Mob;
|
|
import net.minecraft.world.entity.MoverType;
|
|
import net.minecraft.world.entity.SpawnGroupData;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
import net.minecraft.world.entity.ai.goal.Goal;
|
|
import net.minecraft.world.entity.animal.AgeableWaterCreature;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.ServerLevelAccessor;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.material.FluidState;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
public class Squid
|
|
extends AgeableWaterCreature {
|
|
public float xBodyRot;
|
|
public float xBodyRotO;
|
|
public float zBodyRot;
|
|
public float zBodyRotO;
|
|
public float tentacleMovement;
|
|
public float oldTentacleMovement;
|
|
public float tentacleAngle;
|
|
public float oldTentacleAngle;
|
|
private float speed;
|
|
private float tentacleSpeed;
|
|
private float rotateSpeed;
|
|
private Vec3 movementVector = Vec3.ZERO;
|
|
|
|
public Squid(EntityType<? extends Squid> type, Level level) {
|
|
super((EntityType<? extends AgeableWaterCreature>)type, level);
|
|
this.random.setSeed(this.getId());
|
|
this.tentacleSpeed = 1.0f / (this.random.nextFloat() + 1.0f) * 0.2f;
|
|
}
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.goalSelector.addGoal(0, new SquidRandomMovementGoal(this));
|
|
this.goalSelector.addGoal(1, new SquidFleeGoal());
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0);
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getAmbientSound() {
|
|
return SoundEvents.SQUID_AMBIENT;
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getHurtSound(DamageSource source) {
|
|
return SoundEvents.SQUID_HURT;
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getDeathSound() {
|
|
return SoundEvents.SQUID_DEATH;
|
|
}
|
|
|
|
protected SoundEvent getSquirtSound() {
|
|
return SoundEvents.SQUID_SQUIRT;
|
|
}
|
|
|
|
@Override
|
|
public boolean canBeLeashed() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected float getSoundVolume() {
|
|
return 0.4f;
|
|
}
|
|
|
|
@Override
|
|
protected Entity.MovementEmission getMovementEmission() {
|
|
return Entity.MovementEmission.EVENTS;
|
|
}
|
|
|
|
@Override
|
|
public @Nullable AgeableMob getBreedOffspring(ServerLevel level, AgeableMob partner) {
|
|
return EntityType.SQUID.create(level, EntitySpawnReason.BREEDING);
|
|
}
|
|
|
|
@Override
|
|
protected double getDefaultGravity() {
|
|
return 0.08;
|
|
}
|
|
|
|
@Override
|
|
public void aiStep() {
|
|
super.aiStep();
|
|
this.xBodyRotO = this.xBodyRot;
|
|
this.zBodyRotO = this.zBodyRot;
|
|
this.oldTentacleMovement = this.tentacleMovement;
|
|
this.oldTentacleAngle = this.tentacleAngle;
|
|
this.tentacleMovement += this.tentacleSpeed;
|
|
if ((double)this.tentacleMovement > Math.PI * 2) {
|
|
if (this.level().isClientSide()) {
|
|
this.tentacleMovement = (float)Math.PI * 2;
|
|
} else {
|
|
this.tentacleMovement -= (float)Math.PI * 2;
|
|
if (this.random.nextInt(10) == 0) {
|
|
this.tentacleSpeed = 1.0f / (this.random.nextFloat() + 1.0f) * 0.2f;
|
|
}
|
|
this.level().broadcastEntityEvent(this, (byte)19);
|
|
}
|
|
}
|
|
if (this.isInWater()) {
|
|
if (this.tentacleMovement < (float)Math.PI) {
|
|
float tentacleScale = this.tentacleMovement / (float)Math.PI;
|
|
this.tentacleAngle = Mth.sin(tentacleScale * tentacleScale * (float)Math.PI) * (float)Math.PI * 0.25f;
|
|
if ((double)tentacleScale > 0.75) {
|
|
if (this.isLocalInstanceAuthoritative()) {
|
|
this.setDeltaMovement(this.movementVector);
|
|
}
|
|
this.rotateSpeed = 1.0f;
|
|
} else {
|
|
this.rotateSpeed *= 0.8f;
|
|
}
|
|
} else {
|
|
this.tentacleAngle = 0.0f;
|
|
if (this.isLocalInstanceAuthoritative()) {
|
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.9));
|
|
}
|
|
this.rotateSpeed *= 0.99f;
|
|
}
|
|
Vec3 movement = this.getDeltaMovement();
|
|
double horizontalMovement = movement.horizontalDistance();
|
|
this.yBodyRot += (-((float)Mth.atan2(movement.x, movement.z)) * 57.295776f - this.yBodyRot) * 0.1f;
|
|
this.setYRot(this.yBodyRot);
|
|
this.zBodyRot += (float)Math.PI * this.rotateSpeed * 1.5f;
|
|
this.xBodyRot += (-((float)Mth.atan2(horizontalMovement, movement.y)) * 57.295776f - this.xBodyRot) * 0.1f;
|
|
} else {
|
|
this.tentacleAngle = Mth.abs(Mth.sin(this.tentacleMovement)) * (float)Math.PI * 0.25f;
|
|
if (!this.level().isClientSide()) {
|
|
double yd = this.getDeltaMovement().y;
|
|
yd = this.hasEffect(MobEffects.LEVITATION) ? 0.05 * (double)(this.getEffect(MobEffects.LEVITATION).getAmplifier() + 1) : (yd -= this.getGravity());
|
|
this.setDeltaMovement(0.0, yd * (double)0.98f, 0.0);
|
|
}
|
|
this.xBodyRot += (-90.0f - this.xBodyRot) * 0.02f;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean hurtServer(ServerLevel level, DamageSource source, float damage) {
|
|
if (super.hurtServer(level, source, damage) && this.getLastHurtByMob() != null) {
|
|
this.spawnInk();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private Vec3 rotateVector(Vec3 vec) {
|
|
Vec3 v = vec.xRot(this.xBodyRotO * ((float)Math.PI / 180));
|
|
v = v.yRot(-this.yBodyRotO * ((float)Math.PI / 180));
|
|
return v;
|
|
}
|
|
|
|
private void spawnInk() {
|
|
this.makeSound(this.getSquirtSound());
|
|
Vec3 pos = this.rotateVector(new Vec3(0.0, -1.0, 0.0)).add(this.getX(), this.getY(), this.getZ());
|
|
for (int i = 0; i < 30; ++i) {
|
|
Vec3 dir = this.rotateVector(new Vec3((double)this.random.nextFloat() * 0.6 - 0.3, -1.0, (double)this.random.nextFloat() * 0.6 - 0.3));
|
|
float inkPosOffsetScale = this.isBaby() ? 0.1f : 0.3f;
|
|
Vec3 dirOffset = dir.scale(inkPosOffsetScale + this.random.nextFloat() * 2.0f);
|
|
((ServerLevel)this.level()).sendParticles(this.getInkParticle(), pos.x, pos.y + 0.5, pos.z, 0, dirOffset.x, dirOffset.y, dirOffset.z, 0.1f);
|
|
}
|
|
}
|
|
|
|
protected ParticleOptions getInkParticle() {
|
|
return ParticleTypes.SQUID_INK;
|
|
}
|
|
|
|
@Override
|
|
public void travel(Vec3 input) {
|
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
|
}
|
|
|
|
@Override
|
|
public void handleEntityEvent(byte id) {
|
|
if (id == 19) {
|
|
this.tentacleMovement = 0.0f;
|
|
} else {
|
|
super.handleEntityEvent(id);
|
|
}
|
|
}
|
|
|
|
public boolean hasMovementVector() {
|
|
return this.movementVector.lengthSqr() > (double)1.0E-5f;
|
|
}
|
|
|
|
@Override
|
|
public @Nullable SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData groupData) {
|
|
SpawnGroupData spawnGroupData = Objects.requireNonNullElseGet(groupData, () -> new AgeableMob.AgeableMobGroupData(0.05f));
|
|
return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData);
|
|
}
|
|
|
|
private static class SquidRandomMovementGoal
|
|
extends Goal {
|
|
private final Squid squid;
|
|
|
|
public SquidRandomMovementGoal(Squid squid) {
|
|
this.squid = squid;
|
|
}
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
int noActionTime = this.squid.getNoActionTime();
|
|
if (noActionTime > 100) {
|
|
this.squid.movementVector = Vec3.ZERO;
|
|
} else if (this.squid.getRandom().nextInt(SquidRandomMovementGoal.reducedTickDelay(50)) == 0 || !this.squid.wasTouchingWater || !this.squid.hasMovementVector()) {
|
|
float angle = this.squid.getRandom().nextFloat() * ((float)Math.PI * 2);
|
|
this.squid.movementVector = new Vec3(Mth.cos(angle) * 0.2f, -0.1f + this.squid.getRandom().nextFloat() * 0.2f, Mth.sin(angle) * 0.2f);
|
|
}
|
|
}
|
|
}
|
|
|
|
private class SquidFleeGoal
|
|
extends Goal {
|
|
private static final float SQUID_FLEE_SPEED = 3.0f;
|
|
private static final float SQUID_FLEE_MIN_DISTANCE = 5.0f;
|
|
private static final float SQUID_FLEE_MAX_DISTANCE = 10.0f;
|
|
private int fleeTicks;
|
|
|
|
private SquidFleeGoal() {
|
|
}
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
LivingEntity entity = Squid.this.getLastHurtByMob();
|
|
if (Squid.this.isInWater() && entity != null) {
|
|
return Squid.this.distanceToSqr(entity) < 100.0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void start() {
|
|
this.fleeTicks = 0;
|
|
}
|
|
|
|
@Override
|
|
public boolean requiresUpdateEveryTick() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
++this.fleeTicks;
|
|
LivingEntity lastHurtByMob = Squid.this.getLastHurtByMob();
|
|
if (lastHurtByMob == null) {
|
|
return;
|
|
}
|
|
Vec3 fleeTo = new Vec3(Squid.this.getX() - lastHurtByMob.getX(), Squid.this.getY() - lastHurtByMob.getY(), Squid.this.getZ() - lastHurtByMob.getZ());
|
|
BlockState blockState = Squid.this.level().getBlockState(BlockPos.containing(Squid.this.getX() + fleeTo.x, Squid.this.getY() + fleeTo.y, Squid.this.getZ() + fleeTo.z));
|
|
FluidState fluidState = Squid.this.level().getFluidState(BlockPos.containing(Squid.this.getX() + fleeTo.x, Squid.this.getY() + fleeTo.y, Squid.this.getZ() + fleeTo.z));
|
|
if (fluidState.is(FluidTags.WATER) || blockState.isAir()) {
|
|
double length = fleeTo.length();
|
|
if (length > 0.0) {
|
|
fleeTo.normalize();
|
|
double avoidSpeed = 3.0;
|
|
if (length > 5.0) {
|
|
avoidSpeed -= (length - 5.0) / 5.0;
|
|
}
|
|
if (avoidSpeed > 0.0) {
|
|
fleeTo = fleeTo.scale(avoidSpeed);
|
|
}
|
|
}
|
|
if (blockState.isAir()) {
|
|
fleeTo = fleeTo.subtract(0.0, fleeTo.y, 0.0);
|
|
}
|
|
Squid.this.movementVector = new Vec3(fleeTo.x / 20.0, fleeTo.y / 20.0, fleeTo.z / 20.0);
|
|
}
|
|
if (this.fleeTicks % 10 == 5) {
|
|
Squid.this.level().addParticle(ParticleTypes.BUBBLE, Squid.this.getX(), Squid.this.getY(), Squid.this.getZ(), 0.0, 0.0, 0.0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|