package net.minecraft.world.entity.monster;

import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.ai.goal.RemoveBlockGoal;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import java.util.Random;
import java.util.List;
import net.minecraft.world.level.block.Blocks;
import java.time.temporal.TemporalField;
import java.time.temporal.ChronoField;
import java.time.LocalDate;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.animal.Chicken;
import javax.annotation.Nullable;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import com.mojang.serialization.DynamicOps;
import net.minecraft.nbt.NbtOps;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.Items;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.entity.MobType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.NaturalSpawner;
import net.minecraft.world.entity.SpawnPlacements;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.tags.Tag;
import net.minecraft.tags.FluidTags;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.animal.Turtle;
import net.minecraft.world.entity.animal.IronGolem;
import net.minecraft.world.entity.npc.AbstractVillager;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.MoveThroughVillageGoal;
import net.minecraft.world.entity.ai.goal.ZombieAttackGoal;
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.ai.goal.BreakDoorGoal;
import net.minecraft.world.Difficulty;
import java.util.function.Predicate;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import java.util.UUID;

public class Zombie extends Monster {
    private static final UUID SPEED_MODIFIER_BABY_UUID;
    private static final AttributeModifier SPEED_MODIFIER_BABY;
    private static final EntityDataAccessor<Boolean> DATA_BABY_ID;
    private static final EntityDataAccessor<Integer> DATA_SPECIAL_TYPE_ID;
    private static final EntityDataAccessor<Boolean> DATA_DROWNED_CONVERSION_ID;
    private static final Predicate<Difficulty> DOOR_BREAKING_PREDICATE;
    private final BreakDoorGoal breakDoorGoal;
    private boolean canBreakDoors;
    private int inWaterTime;
    private int conversionTime;
    
    public Zombie(final EntityType<? extends Zombie> aoq, final Level bqb) {
        super(aoq, bqb);
        this.breakDoorGoal = new BreakDoorGoal(this, Zombie.DOOR_BREAKING_PREDICATE);
    }
    
    public Zombie(final Level bqb) {
        this(EntityType.ZOMBIE, bqb);
    }
    
    @Override
    protected void registerGoals() {
        this.goalSelector.addGoal(4, new ZombieAttackTurtleEggGoal(this, 1.0, 3));
        this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0f));
        this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
        this.addBehaviourGoals();
    }
    
    protected void addBehaviourGoals() {
        this.goalSelector.addGoal(2, new ZombieAttackGoal(this, 1.0, false));
        this.goalSelector.addGoal(6, new MoveThroughVillageGoal(this, 1.0, true, 4, this::canBreakDoors));
        this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0));
        this.targetSelector.addGoal(1, new HurtByTargetGoal(this, new Class[0]).setAlertOthers(ZombifiedPiglin.class));
        this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
        this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR));
    }
    
    public static AttributeSupplier.Builder createAttributes() {
        return Monster.createMonsterAttributes().add(Attributes.FOLLOW_RANGE, 35.0).add(Attributes.MOVEMENT_SPEED, 0.23000000417232513).add(Attributes.ATTACK_DAMAGE, 3.0).add(Attributes.ARMOR, 2.0).add(Attributes.SPAWN_REINFORCEMENTS_CHANCE);
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.getEntityData().<Boolean>define(Zombie.DATA_BABY_ID, false);
        this.getEntityData().<Integer>define(Zombie.DATA_SPECIAL_TYPE_ID, 0);
        this.getEntityData().<Boolean>define(Zombie.DATA_DROWNED_CONVERSION_ID, false);
    }
    
    public boolean isUnderWaterConverting() {
        return this.getEntityData().<Boolean>get(Zombie.DATA_DROWNED_CONVERSION_ID);
    }
    
    public boolean canBreakDoors() {
        return this.canBreakDoors;
    }
    
    public void setCanBreakDoors(final boolean boolean1) {
        if (this.supportsBreakDoorGoal()) {
            if (this.canBreakDoors != boolean1) {
                this.canBreakDoors = boolean1;
                ((GroundPathNavigation)this.getNavigation()).setCanOpenDoors(boolean1);
                if (boolean1) {
                    this.goalSelector.addGoal(1, this.breakDoorGoal);
                }
                else {
                    this.goalSelector.removeGoal(this.breakDoorGoal);
                }
            }
        }
        else if (this.canBreakDoors) {
            this.goalSelector.removeGoal(this.breakDoorGoal);
            this.canBreakDoors = false;
        }
    }
    
    protected boolean supportsBreakDoorGoal() {
        return true;
    }
    
    @Override
    public boolean isBaby() {
        return this.getEntityData().<Boolean>get(Zombie.DATA_BABY_ID);
    }
    
    @Override
    protected int getExperienceReward(final Player bec) {
        if (this.isBaby()) {
            this.xpReward *= (int)2.5f;
        }
        return super.getExperienceReward(bec);
    }
    
    @Override
    public void setBaby(final boolean boolean1) {
        this.getEntityData().<Boolean>set(Zombie.DATA_BABY_ID, boolean1);
        if (this.level != null && !this.level.isClientSide) {
            final AttributeInstance apt3 = this.getAttribute(Attributes.MOVEMENT_SPEED);
            apt3.removeModifier(Zombie.SPEED_MODIFIER_BABY);
            if (boolean1) {
                apt3.addTransientModifier(Zombie.SPEED_MODIFIER_BABY);
            }
        }
    }
    
    @Override
    public void onSyncedDataUpdated(final EntityDataAccessor<?> tq) {
        if (Zombie.DATA_BABY_ID.equals(tq)) {
            this.refreshDimensions();
        }
        super.onSyncedDataUpdated(tq);
    }
    
    protected boolean convertsInWater() {
        return true;
    }
    
    @Override
    public void tick() {
        if (!this.level.isClientSide && this.isAlive() && !this.isNoAi()) {
            if (this.isUnderWaterConverting()) {
                --this.conversionTime;
                if (this.conversionTime < 0) {
                    this.doUnderWaterConversion();
                }
            }
            else if (this.convertsInWater()) {
                if (this.isEyeInFluid(FluidTags.WATER)) {
                    ++this.inWaterTime;
                    if (this.inWaterTime >= 600) {
                        this.startUnderWaterConversion(300);
                    }
                }
                else {
                    this.inWaterTime = -1;
                }
            }
        }
        super.tick();
    }
    
    @Override
    public void aiStep() {
        if (this.isAlive()) {
            boolean boolean2 = this.isSunSensitive() && this.isSunBurnTick();
            if (boolean2) {
                final ItemStack bki3 = this.getItemBySlot(EquipmentSlot.HEAD);
                if (!bki3.isEmpty()) {
                    if (bki3.isDamageableItem()) {
                        bki3.setDamageValue(bki3.getDamageValue() + this.random.nextInt(2));
                        if (bki3.getDamageValue() >= bki3.getMaxDamage()) {
                            this.broadcastBreakEvent(EquipmentSlot.HEAD);
                            this.setItemSlot(EquipmentSlot.HEAD, ItemStack.EMPTY);
                        }
                    }
                    boolean2 = false;
                }
                if (boolean2) {
                    this.setSecondsOnFire(8);
                }
            }
        }
        super.aiStep();
    }
    
    private void startUnderWaterConversion(final int integer) {
        this.conversionTime = integer;
        this.getEntityData().<Boolean>set(Zombie.DATA_DROWNED_CONVERSION_ID, true);
    }
    
    protected void doUnderWaterConversion() {
        this.convertToZombieType(EntityType.DROWNED);
        if (!this.isSilent()) {
            this.level.levelEvent(null, 1040, this.blockPosition(), 0);
        }
    }
    
    protected void convertToZombieType(final EntityType<? extends Zombie> aoq) {
        final Zombie bcu3 = this.<Zombie>convertTo(aoq);
        if (bcu3 != null) {
            bcu3.handleAttributes(bcu3.level.getCurrentDifficultyAt(bcu3.blockPosition()).getSpecialMultiplier());
            bcu3.setCanBreakDoors(bcu3.supportsBreakDoorGoal() && this.canBreakDoors());
        }
    }
    
    protected boolean isSunSensitive() {
        return true;
    }
    
    @Override
    public boolean hurt(final DamageSource anw, final float float2) {
        if (super.hurt(anw, float2)) {
            LivingEntity aoy4 = this.getTarget();
            if (aoy4 == null && anw.getEntity() instanceof LivingEntity) {
                aoy4 = (LivingEntity)anw.getEntity();
            }
            if (aoy4 != null && this.level.getDifficulty() == Difficulty.HARD && this.random.nextFloat() < this.getAttributeValue(Attributes.SPAWN_REINFORCEMENTS_CHANCE) && this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) {
                final int integer5 = Mth.floor(this.getX());
                final int integer6 = Mth.floor(this.getY());
                final int integer7 = Mth.floor(this.getZ());
                final Zombie bcu8 = new Zombie(this.level);
                for (int integer8 = 0; integer8 < 50; ++integer8) {
                    final int integer9 = integer5 + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1);
                    final int integer10 = integer6 + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1);
                    final int integer11 = integer7 + Mth.nextInt(this.random, 7, 40) * Mth.nextInt(this.random, -1, 1);
                    final BlockPos fu13 = new BlockPos(integer9, integer10, integer11);
                    final EntityType<?> aoq14 = bcu8.getType();
                    final SpawnPlacements.Type c15 = SpawnPlacements.getPlacementType(aoq14);
                    if (NaturalSpawner.isSpawnPositionOk(c15, this.level, fu13, aoq14) && SpawnPlacements.checkSpawnRules(aoq14, this.level, MobSpawnType.REINFORCEMENT, fu13, this.level.random)) {
                        bcu8.setPos(integer9, integer10, integer11);
                        if (!this.level.hasNearbyAlivePlayer(integer9, integer10, integer11, 7.0) && this.level.isUnobstructed(bcu8) && this.level.noCollision(bcu8) && !this.level.containsAnyLiquid(bcu8.getBoundingBox())) {
                            this.level.addFreshEntity(bcu8);
                            bcu8.setTarget(aoy4);
                            bcu8.finalizeSpawn(this.level, this.level.getCurrentDifficultyAt(bcu8.blockPosition()), MobSpawnType.REINFORCEMENT, null, null);
                            this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).addPermanentModifier(new AttributeModifier("Zombie reinforcement caller charge", -0.05000000074505806, AttributeModifier.Operation.ADDITION));
                            bcu8.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).addPermanentModifier(new AttributeModifier("Zombie reinforcement callee charge", -0.05000000074505806, AttributeModifier.Operation.ADDITION));
                            break;
                        }
                    }
                }
            }
            return true;
        }
        return false;
    }
    
    @Override
    public boolean doHurtTarget(final Entity aom) {
        final boolean boolean3 = super.doHurtTarget(aom);
        if (boolean3) {
            final float float4 = this.level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty();
            if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < float4 * 0.3f) {
                aom.setSecondsOnFire(2 * (int)float4);
            }
        }
        return boolean3;
    }
    
    @Override
    protected SoundEvent getAmbientSound() {
        return SoundEvents.ZOMBIE_AMBIENT;
    }
    
    @Override
    protected SoundEvent getHurtSound(final DamageSource anw) {
        return SoundEvents.ZOMBIE_HURT;
    }
    
    @Override
    protected SoundEvent getDeathSound() {
        return SoundEvents.ZOMBIE_DEATH;
    }
    
    protected SoundEvent getStepSound() {
        return SoundEvents.ZOMBIE_STEP;
    }
    
    @Override
    protected void playStepSound(final BlockPos fu, final BlockState cfj) {
        this.playSound(this.getStepSound(), 0.15f, 1.0f);
    }
    
    @Override
    public MobType getMobType() {
        return MobType.UNDEAD;
    }
    
    @Override
    protected void populateDefaultEquipmentSlots(final DifficultyInstance ane) {
        super.populateDefaultEquipmentSlots(ane);
        if (this.random.nextFloat() < ((this.level.getDifficulty() == Difficulty.HARD) ? 0.05f : 0.01f)) {
            final int integer3 = this.random.nextInt(3);
            if (integer3 == 0) {
                this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SWORD));
            }
            else {
                this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.IRON_SHOVEL));
            }
        }
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag le) {
        super.addAdditionalSaveData(le);
        if (this.isBaby()) {
            le.putBoolean("IsBaby", true);
        }
        le.putBoolean("CanBreakDoors", this.canBreakDoors());
        le.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1);
        le.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1);
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag le) {
        super.readAdditionalSaveData(le);
        if (le.getBoolean("IsBaby")) {
            this.setBaby(true);
        }
        this.setCanBreakDoors(le.getBoolean("CanBreakDoors"));
        this.inWaterTime = le.getInt("InWaterTime");
        if (le.contains("DrownedConversionTime", 99) && le.getInt("DrownedConversionTime") > -1) {
            this.startUnderWaterConversion(le.getInt("DrownedConversionTime"));
        }
    }
    
    @Override
    public void killed(final LivingEntity aoy) {
        super.killed(aoy);
        if ((this.level.getDifficulty() == Difficulty.NORMAL || this.level.getDifficulty() == Difficulty.HARD) && aoy instanceof Villager) {
            if (this.level.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) {
                return;
            }
            final Villager bdp3 = (Villager)aoy;
            final ZombieVillager bcv4 = EntityType.ZOMBIE_VILLAGER.create(this.level);
            bcv4.copyPosition(bdp3);
            bdp3.remove();
            bcv4.finalizeSpawn(this.level, this.level.getCurrentDifficultyAt(bcv4.blockPosition()), MobSpawnType.CONVERSION, new ZombieGroupData(false, true), null);
            bcv4.setVillagerData(bdp3.getVillagerData());
            bcv4.setGossips((net.minecraft.nbt.Tag)bdp3.getGossips().store((com.mojang.serialization.DynamicOps<Object>)NbtOps.INSTANCE).getValue());
            bcv4.setTradeOffers(bdp3.getOffers().createTag());
            bcv4.setVillagerXp(bdp3.getVillagerXp());
            bcv4.setBaby(bdp3.isBaby());
            bcv4.setNoAi(bdp3.isNoAi());
            if (bdp3.hasCustomName()) {
                bcv4.setCustomName(bdp3.getCustomName());
                bcv4.setCustomNameVisible(bdp3.isCustomNameVisible());
            }
            if (bdp3.isPersistenceRequired()) {
                bcv4.setPersistenceRequired();
            }
            bcv4.setInvulnerable(this.isInvulnerable());
            this.level.addFreshEntity(bcv4);
            if (!this.isSilent()) {
                this.level.levelEvent(null, 1026, this.blockPosition(), 0);
            }
        }
    }
    
    @Override
    protected float getStandingEyeHeight(final Pose apj, final EntityDimensions aon) {
        return this.isBaby() ? 0.93f : 1.74f;
    }
    
    @Override
    public boolean canHoldItem(final ItemStack bki) {
        return (bki.getItem() != Items.EGG || !this.isBaby() || !this.isPassenger()) && super.canHoldItem(bki);
    }
    
    @Nullable
    @Override
    public SpawnGroupData finalizeSpawn(final LevelAccessor bqc, final DifficultyInstance ane, final MobSpawnType apb, @Nullable SpawnGroupData apo, @Nullable final CompoundTag le) {
        apo = super.finalizeSpawn(bqc, ane, apb, apo, le);
        final float float7 = ane.getSpecialMultiplier();
        this.setCanPickUpLoot(this.random.nextFloat() < 0.55f * float7);
        if (apo == null) {
            apo = new ZombieGroupData(getSpawnAsBabyOdds(bqc.getRandom()), true);
        }
        if (apo instanceof ZombieGroupData) {
            final ZombieGroupData b8 = (ZombieGroupData)apo;
            if (b8.isBaby) {
                this.setBaby(true);
                if (b8.canSpawnJockey) {
                    if (bqc.getRandom().nextFloat() < 0.05) {
                        final List<Chicken> list9 = bqc.<Chicken>getEntitiesOfClass(Chicken.class, this.getBoundingBox().inflate(5.0, 3.0, 5.0), EntitySelector.ENTITY_NOT_BEING_RIDDEN);
                        if (!list9.isEmpty()) {
                            final Chicken ayn10 = list9.get(0);
                            ayn10.setChickenJockey(true);
                            this.startRiding(ayn10);
                        }
                    }
                    else if (bqc.getRandom().nextFloat() < 0.05) {
                        final Chicken ayn11 = EntityType.CHICKEN.create(this.level);
                        ayn11.moveTo(this.getX(), this.getY(), this.getZ(), this.yRot, 0.0f);
                        ayn11.finalizeSpawn(bqc, ane, MobSpawnType.JOCKEY, null, null);
                        ayn11.setChickenJockey(true);
                        this.startRiding(ayn11);
                        bqc.addFreshEntity(ayn11);
                    }
                }
            }
            this.setCanBreakDoors(this.supportsBreakDoorGoal() && this.random.nextFloat() < float7 * 0.1f);
            this.populateDefaultEquipmentSlots(ane);
            this.populateDefaultEquipmentEnchantments(ane);
        }
        if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
            final LocalDate localDate8 = LocalDate.now();
            final int integer9 = localDate8.get(ChronoField.DAY_OF_MONTH);
            final int integer10 = localDate8.get(ChronoField.MONTH_OF_YEAR);
            if (integer10 == 10 && integer9 == 31 && this.random.nextFloat() < 0.25f) {
                this.setItemSlot(EquipmentSlot.HEAD, new ItemStack((this.random.nextFloat() < 0.1f) ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
                this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0f;
            }
        }
        this.handleAttributes(float7);
        return apo;
    }
    
    public static boolean getSpawnAsBabyOdds(final Random random) {
        return random.nextFloat() < 0.05f;
    }
    
    protected void handleAttributes(final float float1) {
        this.randomizeReinforcementsChance();
        this.getAttribute(Attributes.KNOCKBACK_RESISTANCE).addPermanentModifier(new AttributeModifier("Random spawn bonus", this.random.nextDouble() * 0.05000000074505806, AttributeModifier.Operation.ADDITION));
        final double double3 = this.random.nextDouble() * 1.5 * float1;
        if (double3 > 1.0) {
            this.getAttribute(Attributes.FOLLOW_RANGE).addPermanentModifier(new AttributeModifier("Random zombie-spawn bonus", double3, AttributeModifier.Operation.MULTIPLY_TOTAL));
        }
        if (this.random.nextFloat() < float1 * 0.05f) {
            this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).addPermanentModifier(new AttributeModifier("Leader zombie bonus", this.random.nextDouble() * 0.25 + 0.5, AttributeModifier.Operation.ADDITION));
            this.getAttribute(Attributes.MAX_HEALTH).addPermanentModifier(new AttributeModifier("Leader zombie bonus", this.random.nextDouble() * 3.0 + 1.0, AttributeModifier.Operation.MULTIPLY_TOTAL));
            this.setCanBreakDoors(this.supportsBreakDoorGoal());
        }
    }
    
    protected void randomizeReinforcementsChance() {
        this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE).setBaseValue(this.random.nextDouble() * 0.10000000149011612);
    }
    
    @Override
    public double getMyRidingOffset() {
        return this.isBaby() ? 0.0 : -0.45;
    }
    
    @Override
    protected void dropCustomDeathLoot(final DamageSource anw, final int integer, final boolean boolean3) {
        super.dropCustomDeathLoot(anw, integer, boolean3);
        final Entity aom5 = anw.getEntity();
        if (aom5 instanceof Creeper) {
            final Creeper bbn6 = (Creeper)aom5;
            if (bbn6.canDropMobsSkull()) {
                bbn6.increaseDroppedSkulls();
                final ItemStack bki7 = this.getSkull();
                if (!bki7.isEmpty()) {
                    this.spawnAtLocation(bki7);
                }
            }
        }
    }
    
    protected ItemStack getSkull() {
        return new ItemStack(Items.ZOMBIE_HEAD);
    }
    
    static {
        SPEED_MODIFIER_BABY_UUID = UUID.fromString("B9766B59-9566-4402-BC1F-2EE2A276D836");
        SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5, AttributeModifier.Operation.MULTIPLY_BASE);
        DATA_BABY_ID = SynchedEntityData.<Boolean>defineId(Zombie.class, EntityDataSerializers.BOOLEAN);
        DATA_SPECIAL_TYPE_ID = SynchedEntityData.<Integer>defineId(Zombie.class, EntityDataSerializers.INT);
        DATA_DROWNED_CONVERSION_ID = SynchedEntityData.<Boolean>defineId(Zombie.class, EntityDataSerializers.BOOLEAN);
        DOOR_BREAKING_PREDICATE = (and -> and == Difficulty.HARD);
    }
    
    public static class ZombieGroupData implements SpawnGroupData {
        public final boolean isBaby;
        public final boolean canSpawnJockey;
        
        public ZombieGroupData(final boolean boolean1, final boolean boolean2) {
            this.isBaby = boolean1;
            this.canSpawnJockey = boolean2;
        }
    }
    
    class ZombieAttackTurtleEggGoal extends RemoveBlockGoal {
        ZombieAttackTurtleEggGoal(final PathfinderMob apg, final double double3, final int integer) {
            super(Blocks.TURTLE_EGG, apg, double3, integer);
        }
        
        @Override
        public void playDestroyProgressSound(final LevelAccessor bqc, final BlockPos fu) {
            bqc.playSound(null, fu, SoundEvents.ZOMBIE_DESTROY_EGG, SoundSource.HOSTILE, 0.5f, 0.9f + Zombie.this.random.nextFloat() * 0.2f);
        }
        
        @Override
        public void playBreakSound(final Level bqb, final BlockPos fu) {
            bqb.playSound(null, fu, SoundEvents.TURTLE_EGG_BREAK, SoundSource.BLOCKS, 0.7f, 0.9f + bqb.random.nextFloat() * 0.2f);
        }
        
        @Override
        public double acceptedDistance() {
            return 1.14;
        }
    }
}
