minecraft-source/src/net/minecraft/world/entity/animal/Ocelot.java

313 lines
12 KiB
Java

package net.minecraft.world.entity.animal;
import net.minecraft.world.entity.ai.goal.TemptGoal;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.LevelReader;
import java.util.Random;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.entity.AgableMob;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.damagesource.DamageSource;
import javax.annotation.Nullable;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.monster.SharedMonsterAttributes;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.BreedGoal;
import net.minecraft.world.entity.ai.goal.OcelotAttackGoal;
import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.item.crafting.Ingredient;
public class Ocelot extends Animal {
private static final Ingredient TEMPT_INGREDIENT;
private static final EntityDataAccessor<Boolean> DATA_TRUSTING;
private OcelotAvoidEntityGoal<Player> ocelotAvoidPlayersGoal;
private OcelotTemptGoal temptGoal;
public Ocelot(final EntityType<? extends Ocelot> akr, final Level bjt) {
super(akr, bjt);
this.reassessTrustingGoals();
}
private boolean isTrusting() {
return this.entityData.<Boolean>get(Ocelot.DATA_TRUSTING);
}
private void setTrusting(final boolean boolean1) {
this.entityData.<Boolean>set(Ocelot.DATA_TRUSTING, boolean1);
this.reassessTrustingGoals();
}
@Override
public void addAdditionalSaveData(final CompoundTag jt) {
super.addAdditionalSaveData(jt);
jt.putBoolean("Trusting", this.isTrusting());
}
@Override
public void readAdditionalSaveData(final CompoundTag jt) {
super.readAdditionalSaveData(jt);
this.setTrusting(jt.getBoolean("Trusting"));
}
@Override
protected void defineSynchedData() {
super.defineSynchedData();
this.entityData.<Boolean>define(Ocelot.DATA_TRUSTING, false);
}
@Override
protected void registerGoals() {
this.temptGoal = new OcelotTemptGoal(this, 0.6, Ocelot.TEMPT_INGREDIENT, true);
this.goalSelector.addGoal(1, new FloatGoal(this));
this.goalSelector.addGoal(3, this.temptGoal);
this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3f));
this.goalSelector.addGoal(8, new OcelotAttackGoal(this));
this.goalSelector.addGoal(9, new BreedGoal(this, 0.8));
this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal(this, 0.8, 1.0000001E-5f));
this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0f));
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Chicken.class, false));
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR));
}
public void customServerAiStep() {
if (this.getMoveControl().hasWanted()) {
final double double2 = this.getMoveControl().getSpeedModifier();
if (double2 == 0.6) {
this.setPose(Pose.CROUCHING);
this.setSprinting(false);
}
else if (double2 == 1.33) {
this.setPose(Pose.STANDING);
this.setSprinting(true);
}
else {
this.setPose(Pose.STANDING);
this.setSprinting(false);
}
}
else {
this.setPose(Pose.STANDING);
this.setSprinting(false);
}
}
@Override
public boolean removeWhenFarAway(final double double1) {
return !this.isTrusting() && this.tickCount > 2400;
}
@Override
protected void registerAttributes() {
super.registerAttributes();
this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(10.0);
this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.30000001192092896);
this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(3.0);
}
@Override
public boolean causeFallDamage(final float float1, final float float2) {
return false;
}
@Nullable
@Override
protected SoundEvent getAmbientSound() {
return SoundEvents.OCELOT_AMBIENT;
}
@Override
public int getAmbientSoundInterval() {
return 900;
}
@Override
protected SoundEvent getHurtSound(final DamageSource ajw) {
return SoundEvents.OCELOT_HURT;
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.OCELOT_DEATH;
}
private float getAttackDamage() {
return (float)this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getValue();
}
@Override
public boolean doHurtTarget(final Entity akn) {
return akn.hurt(DamageSource.mobAttack(this), this.getAttackDamage());
}
@Override
public boolean hurt(final DamageSource ajw, final float float2) {
return !this.isInvulnerableTo(ajw) && super.hurt(ajw, float2);
}
@Override
public boolean mobInteract(final Player ayg, final InteractionHand ajh) {
final ItemStack bek4 = ayg.getItemInHand(ajh);
if ((this.temptGoal == null || this.temptGoal.isRunning()) && !this.isTrusting() && this.isFood(bek4) && ayg.distanceToSqr(this) < 9.0) {
this.usePlayerItem(ayg, bek4);
if (!this.level.isClientSide) {
if (this.random.nextInt(3) == 0) {
this.setTrusting(true);
this.spawnTrustingParticles(true);
this.level.broadcastEntityEvent(this, (byte)41);
}
else {
this.spawnTrustingParticles(false);
this.level.broadcastEntityEvent(this, (byte)40);
}
}
return true;
}
return super.mobInteract(ayg, ajh);
}
@Override
public void handleEntityEvent(final byte byte1) {
if (byte1 == 41) {
this.spawnTrustingParticles(true);
}
else if (byte1 == 40) {
this.spawnTrustingParticles(false);
}
else {
super.handleEntityEvent(byte1);
}
}
private void spawnTrustingParticles(final boolean boolean1) {
ParticleOptions gt3 = ParticleTypes.HEART;
if (!boolean1) {
gt3 = ParticleTypes.SMOKE;
}
for (int integer4 = 0; integer4 < 7; ++integer4) {
final double double5 = this.random.nextGaussian() * 0.02;
final double double6 = this.random.nextGaussian() * 0.02;
final double double7 = this.random.nextGaussian() * 0.02;
this.level.addParticle(gt3, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), double5, double6, double7);
}
}
protected void reassessTrustingGoals() {
if (this.ocelotAvoidPlayersGoal == null) {
this.ocelotAvoidPlayersGoal = new OcelotAvoidEntityGoal<Player>(this, Player.class, 16.0f, 0.8, 1.33);
}
this.goalSelector.removeGoal(this.ocelotAvoidPlayersGoal);
if (!this.isTrusting()) {
this.goalSelector.addGoal(4, this.ocelotAvoidPlayersGoal);
}
}
@Override
public Ocelot getBreedOffspring(final AgableMob akl) {
return EntityType.OCELOT.create(this.level);
}
@Override
public boolean isFood(final ItemStack bek) {
return Ocelot.TEMPT_INGREDIENT.test(bek);
}
public static boolean checkOcelotSpawnRules(final EntityType<Ocelot> akr, final LevelAccessor bju, final MobSpawnType akz, final BlockPos fk, final Random random) {
return random.nextInt(3) != 0;
}
@Override
public boolean checkSpawnObstruction(final LevelReader bjw) {
if (bjw.isUnobstructed(this) && !bjw.containsAnyLiquid(this.getBoundingBox())) {
final BlockPos fk3 = new BlockPos(this);
if (fk3.getY() < bjw.getSeaLevel()) {
return false;
}
final BlockState byg4 = bjw.getBlockState(fk3.below());
final Block bpe5 = byg4.getBlock();
if (bpe5 == Blocks.GRASS_BLOCK || byg4.is(BlockTags.LEAVES)) {
return true;
}
}
return false;
}
@Nullable
@Override
public SpawnGroupData finalizeSpawn(final LevelAccessor bju, final DifficultyInstance ajg, final MobSpawnType akz, @Nullable SpawnGroupData alj, @Nullable final CompoundTag jt) {
if (alj == null) {
alj = new AgableMobGroupData();
((AgableMobGroupData)alj).setBabySpawnChance(1.0f);
}
return super.finalizeSpawn(bju, ajg, akz, alj, jt);
}
static {
TEMPT_INGREDIENT = Ingredient.of(Items.COD, Items.SALMON);
DATA_TRUSTING = SynchedEntityData.<Boolean>defineId(Ocelot.class, EntityDataSerializers.BOOLEAN);
}
static class OcelotAvoidEntityGoal<T extends LivingEntity> extends AvoidEntityGoal<T> {
private final Ocelot ocelot;
public OcelotAvoidEntityGoal(final Ocelot atk, final Class<T> class2, final float float3, final double double4, final double double5) {
super(atk, class2, float3, double4, double5, EntitySelector.NO_CREATIVE_OR_SPECTATOR::test);
this.ocelot = atk;
}
@Override
public boolean canUse() {
return !this.ocelot.isTrusting() && super.canUse();
}
@Override
public boolean canContinueToUse() {
return !this.ocelot.isTrusting() && super.canContinueToUse();
}
}
static class OcelotTemptGoal extends TemptGoal {
private final Ocelot ocelot;
public OcelotTemptGoal(final Ocelot atk, final double double2, final Ingredient bgq, final boolean boolean4) {
super(atk, double2, bgq, boolean4);
this.ocelot = atk;
}
@Override
protected boolean canScare() {
return super.canScare() && !this.ocelot.isTrusting();
}
}
}