code:
package astrotibs.notenoughpets.entity;

import java.lang.reflect.Method;

import javax.annotation.Nullable;

import astrotibs.notenoughpets.ai.EntityAIFollowOwnerNEP;
import astrotibs.notenoughpets.ai.EntityAITemptNEP;
import astrotibs.notenoughpets.config.GeneralConfig;
import astrotibs.notenoughpets.util.FunctionsNEP;
import astrotibs.notenoughpets.util.Reference;
import astrotibs.notenoughpets.util.SkinVariations;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.ai.EntityAITempt;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.passive.EntityOcelot;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundEvent;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.ReflectionHelper;

public class EntityOcelotNEP extends EntityOcelot {

	private static final DataParameter<Integer> COLLAR_COLOR = EntityDataManager.<Integer>createKey(EntityOcelotNEP.class, DataSerializers.VARINT);
	private static final DataParameter<Integer> NEP_AGE = EntityDataManager.<Integer>createKey(EntityOcelotNEP.class, DataSerializers.VARINT);

	public EntityOcelotNEP(World world)
	{
		super(world);
		EntityAIFollowOwnerNEP.removeVanillaFollow(this);
		EntityAITemptNEP.removeVanillaTempt(this);

		// New tempt
		String[] aiTempt_fields = new String[]{"aiTempt", "field_70914_e"};
		ReflectionHelper.setPrivateValue(EntityOcelot.class, this, new EntityAITemptNEP(this, 0.6D, Items.FISH, true), aiTempt_fields); // fish is a placeholder
		this.tasks.addTask(3, (EntityAIBase)ReflectionHelper.getPrivateValue(EntityOcelot.class, this, aiTempt_fields));

		// New follow
		if (GeneralConfig.followOwnerCat) {this.tasks.addTask(5, new EntityAIFollowOwnerNEP(this, 1.0D, 10.0F, 5.0F));}
	}

	@Override
	protected void entityInit()
	{
		super.entityInit();
		// A datawatcher value to represent collar color
		this.dataManager.register(COLLAR_COLOR, Integer.valueOf(EnumDyeColor.RED.getDyeDamage()));
		//this.dataWatcher.addObject(20, new Byte((byte)EnumDyeColor.RED.getMetadata()));

        // A datawatcher value to represent age, because stupid 1.8+ culls it to a byte
		this.dataManager.register(NEP_AGE, Integer.valueOf(0));
	}

	@Override
    public int getGrowingAge()
    {
		return this.dataManager.get(NEP_AGE);
    }

	@Override
    public void setGrowingAge(int age)
    {
		super.setGrowingAge(age);
		this.dataManager.set(NEP_AGE, age);
    }

	/**
     * (abstract) Protected helper method to write subclass entity data to NBT.
     */
	@Override
    public void writeEntityToNBT(NBTTagCompound tagCompound)
    {
        super.writeEntityToNBT(tagCompound);
        tagCompound.setByte("CollarColor", (byte)this.getCollarColor().getDyeDamage());
    }

	/**
     * (abstract) Protected helper method to read subclass entity data from NBT.
     */
	@Override
    public void readEntityFromNBT(NBTTagCompound tagCompound)
    {
        super.readEntityFromNBT(tagCompound);

        if (tagCompound.hasKey("CollarColor", 99))
        {
            this.setCollarColor(EnumDyeColor.byDyeDamage(tagCompound.getByte("CollarColor")));
        }
    }

	@Override
	public void onLivingUpdate()
	{
		super.onLivingUpdate();

		// If this is not an Ocelot, make it avoid water
		if ( this.getTameSkin()!=0 && !(this.getPathPriority(PathNodeType.WATER)>=0) ) {
			//((PathNavigateGround)this.getNavigator()).setAvoidsWater(true);
			this.setPathPriority(PathNodeType.WATER, -1.0F);
		}
		else if ( this.getTameSkin()==0 && (this.getPathPriority(PathNodeType.WATER)<0) ) {
			//((PathNavigateGround)this.getNavigator()).setAvoidsWater(false);
			this.setPathPriority(PathNodeType.WATER, 0.0F);
		}
		//this.tasks.removeTask( this.followTaskOld );
	}

	// No longer drop leather in 1.9
	/*
	@Override
	protected Item getDropItem()
    {
		if (this.getTameSkin()==0 && this.getGrowingAge()>=0 )
		{
			return Items.LEATHER;
		}
		else return null;
    }
    */

    /**
     * If this is not an ocelot or kitten, drop string
     */
	@Override
    protected void dropFewItems(boolean recentlyHit, int looting)
    {
		if (this.getTameSkin()!=0 && this.getGrowingAge()>=0)
		{
	        int i = this.rand.nextInt(3) + this.rand.nextInt(looting + 1);

	        if (i > 0)
	        {
	            this.entityDropItem(new ItemStack(Items.STRING, i, 0), 1.0F);
	        }
		}

    }

    /**
     * Called when a player interacts with a mob. Specifically, giving a fish to the kitty.
     */
	@Override
    public boolean processInteract(EntityPlayer player, EnumHand hand, @Nullable ItemStack itemstack)
    {
		EntityAITempt aiTempt_f = ReflectionHelper.getPrivateValue( EntityOcelot.class, this, new String[]{"aiTempt", "field_70914_e"} );

        if (this.isTamed())
        {
        	if (itemstack!=null)
            {
        		// Dye the collar
        		if (itemstack.getItem() == Items.DYE)
        		{
        			EnumDyeColor enumdyecolor = EnumDyeColor.byDyeDamage(itemstack.getMetadata());

                    if (enumdyecolor != this.getCollarColor())
                    {
                        this.setCollarColor(enumdyecolor);

                        if (!player.capabilities.isCreativeMode) {--itemstack.stackSize;}
                        if (!this.isSilent()) {this.playSound(Reference.SE_DYE_COLLAR, this.getOcelotVolume(), 1F);}

        				return true;
                    }
        		}
        		// Heal the cat
        		else if (FunctionsNEP.isItemStackOnList(itemstack, GeneralConfig.catBreedingItem_a))
        		{
        			if (this.isBreedingItem(itemstack) && (this.getHealth() < this.getMaxHealth()) && GeneralConfig.healingFoodCat)
        			{
        				if (!player.capabilities.isCreativeMode) {--itemstack.stackSize;}
        				if (!this.isSilent()) {this.playSound(Reference.SE_CAT_EAT, this.getOcelotVolume(), FunctionsNEP.getScaledSoundPitch(this));}
        				float healAmount = itemstack.getItem() instanceof ItemFood ? ((ItemFood)itemstack.getItem()).getHealAmount(itemstack) : GeneralConfig.catFeedingItemsDefaultAmount;
        				this.heal(healAmount);
        				this.playTameEffect(true); // True is hearts

        				return true;
        			}
        		}
        		else if (itemstack.getItem()==Items.FISH)
        		{
        			// Item is a vanilla food for this animal but WASN'T on the config list
        			return false;
        		}
            }

        }
        // Try to tame the cat
        else if ((aiTempt_f == null || aiTempt_f.isRunning()) && this.isBreedingItem(itemstack) && player.getDistanceSqToEntity(this) < 9.0D)
        {
            if (!player.capabilities.isCreativeMode) {--itemstack.stackSize;}

            if (!this.worldObj.isRemote)
            {
            	// Added in v 1.1
            	// Munch sound plays when trying to tame the cat
            	// Changed in v1.2 - pitch scales with age
            	if (!this.isSilent()) {this.playSound(Reference.SE_CAT_EAT, this.getOcelotVolume(), FunctionsNEP.getScaledSoundPitch(this));}

                if (this.rand.nextInt(3) == 0)
                {
                	this.setTamed(true);
                	this.setOwnerId(player.getUniqueID());
                    this.playTameEffect(true);
                    this.aiSit.setSitting(true);
                    this.worldObj.setEntityState(this, (byte)7);
                }
                else
                {
                    this.playTameEffect(false);
                    this.worldObj.setEntityState(this, (byte)6);
                }
            }

            return true;
        }

        // Play generic eating sound with food
        if (itemstack != null
        		&& this.isBreedingItem(itemstack))
        {
            EntityAITempt aiTempt_reflected = ReflectionHelper.getPrivateValue( EntityOcelot.class, this, new String[]{"aiTempt", "field_70914_e"} );

        	if (
        			!this.isSilent() && (
        			// When taming
        			((aiTempt_reflected == null || aiTempt_reflected.isRunning()) && player.getDistanceSqToEntity(this) < 9.0D)
        			// When breeding
        			|| (this.getGrowingAge() == 0 && !this.isInLove())
        			// When raising
        			|| (this.isChild()))
        			)
        		{this.playSound(Reference.SE_CAT_EAT, this.getOcelotVolume(), FunctionsNEP.getScaledSoundPitch(this));}

    		return super.processInteract(player, hand, itemstack);
        }
        // Toggle sitting
        if (this.isOwner(player) && !this.worldObj.isRemote && !(itemstack!=null && this.isBreedingItem(itemstack) && this.getGrowingAge() == 0 && !this.isInLove()))
        {
        	this.aiSit.setSitting(!this.isSitting());
        }

        // Fall back onto super
        return super.processInteract(player, hand, itemstack);
    }

	/**
     * Forces the baby to be the NEC type - v1.3.0
     */
	@Override
	public EntityOcelotNEP createChild(EntityAgeable otherParent)
    {
		EntityOcelotNEP babyOcelot = new EntityOcelotNEP(this.worldObj);

        if (this.isTamed())
        {
            babyOcelot.setOwnerId(this.getOwnerId());
            babyOcelot.setTamed(true);
            // Set the offspring to a random variant based on the parents - v2.0.0
            try
            {
            	babyOcelot.setTameSkin( this.worldObj.rand.nextBoolean() ? this.getTameSkin() : ((EntityOcelotNEP)otherParent).getTameSkin() );
            }
            catch (Exception e) {babyOcelot.setTameSkin(this.getTameSkin());}
            // v2.0.0 randomly select a skin that has nothing to do with the parents - MUTATION!
            if (this.worldObj.rand.nextInt(1000)==0) {babyOcelot.setTameSkin(SkinVariations.catSkinArray.length);}
        }
        return babyOcelot;
    }

	// Added in v1.2
	/**
     * Gets the pitch of living sounds in living entities.
     */
	@Override
    protected float getSoundPitch()
    {
		return FunctionsNEP.getScaledSoundPitch(this);
    }

	// Turned off babies because I don't want them with spawn eggs. They spawn just fine vanilla-style - v1.4.0
	@Override
    public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData ientitylivingdata)
    {
        //ientitylivingdata = super.onInitialSpawn(difficulty, ientitylivingdata);
		this.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE).applyModifier(new AttributeModifier("Random spawn bonus", this.rand.nextGaussian() * 0.05D, 1));

        /*
        // Make kittens!
        if (this.worldObj.rand.nextInt(7) == 0)
        {
        	// Make them each be 50/50 between having this parent's skin and another arbitrary parent's skin

        	int otherParentType=0;
        	// This is not a jungle ocelot
        	if (!(this.getTameSkin()==0)) {otherParentType = this.worldObj.rand.nextInt(SkinVariations.catSkinArray.length-1)+1;} // Changed in v1.2.1

            for (int i = 0; i < 2; ++i)
            {
            	EntityOcelotNEC entityocelot = new EntityOcelotNEC(this.worldObj); // Changed in v1.3.0
                entityocelot.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, 0.0F);
                entityocelot.setGrowingAge(-24000);
                entityocelot.setTameSkin(this.worldObj.rand.nextBoolean() ? this.getTameSkin() : otherParentType);
                this.worldObj.spawnEntityInWorld(entityocelot);
            }
        }
		*/
        return ientitylivingdata;
    }

	// All sound entries re-written in v 1.1
	@Override
	protected SoundEvent getAmbientSound()
	{
		if (this.isTamed())
		{
			// Suppression only applies to tamed - v2.0.0
			if (rand.nextInt(100) < GeneralConfig.soundOccurrenceCat)
			{
				if (this.isInLove())
				{
					return SoundEvents.ENTITY_CAT_PURR;
				}
				else
				{
					if (this.getTameSkin()==0)
					{
						return Reference.SE_CAT_OCELOT_IDLE; // Ocelot idle sound
					}
					else
					{
						return (this.rand.nextInt(4) == 0 ?
								SoundEvents.ENTITY_CAT_PURREOW :
									SoundEvents.ENTITY_CAT_AMBIENT
									); // Non-ocelot idle sound
					}
				}
			}
		}
		else
		{
			EntityAITempt aiTempt_f = ReflectionHelper.getPrivateValue(
					EntityOcelot.class, this, new String[]{"aiTempt", "field_70914_e"});

			if (
					aiTempt_f != null &&
					aiTempt_f.isRunning() // "Running" means "executing"
					)
	        {
				return Reference.SE_CAT_BEG; // Cat is begging for fishies
	        }
			else
			{
				if (!(this.getTameSkin()==0))
				{
					return Reference.SE_CAT_STRAY_IDLE; // Sound made when not tamed and not an ocelot
				}
			}
		}
		return null;
	}
	// Cancel hurt and death sounds: they are covered in the event handler.
	@Override
    protected SoundEvent getHurtSound()
    {
		return null;
    }
	@Override
    protected SoundEvent getDeathSound()
    {
		return null;
    }

    /**
     * Return this ocelot's collar color.
     */
	public EnumDyeColor getCollarColor()
    {
		return EnumDyeColor.byDyeDamage(((Integer)this.dataManager.get(COLLAR_COLOR)).intValue() & 15);
    }

    /**
     * Set this ocelot's collar color.
     */
    public void setCollarColor(EnumDyeColor collarcolor)
    {
    	this.dataManager.set(COLLAR_COLOR, Integer.valueOf(collarcolor.getDyeDamage()));
    }

	/**
	 * This accesses the EntityOcelot.getSoundVolume() value, which is 0.4F.
	 * This method exists just in case some other mod wants to adjust that value.
	 */
	public float getOcelotVolume() {

		try {
			Method getSoundVolume_m = ReflectionHelper.findMethod(EntityOcelot.class, this, new String[]{"getSoundVolume", "func_70599_aP"});
			return (Float)getSoundVolume_m.invoke(this);
			}
		catch (Exception e) {}

		return 0.4F;
	}

    /**
     * Checks if the parameter is an item which this animal can be fed to breed it
     */
    @Override
    public boolean isBreedingItem(ItemStack itemStack)
    {
    	return itemStack == null ? false : FunctionsNEP.isItemStackOnList(itemStack, GeneralConfig.catBreedingItem_a);
    }
}


code:
package astrotibs.notenoughpets.entity;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.annotation.Nullable;

import com.google.common.base.Predicate;
import com.google.common.collect.Maps;

import astrotibs.notenoughpets.ai.EntityAIFollowOwnerNEP;
import astrotibs.notenoughpets.ai.minecraft.EntityAIFollowOwnerFlying;
import astrotibs.notenoughpets.ai.minecraft.EntityAIFollowParrot;
import astrotibs.notenoughpets.ai.minecraft.EntityAILandOnOwnersShoulder;
import astrotibs.notenoughpets.ai.minecraft.EntityAISwimmingNEP;
import astrotibs.notenoughpets.ai.minecraft.EntityAIWanderAvoidWaterFlying;
import astrotibs.notenoughpets.ai.minecraft.EntityFlyHelper;
import astrotibs.notenoughpets.config.GeneralConfig;
import astrotibs.notenoughpets.pathfinding.minecraft.PathNavigateFlying;
import astrotibs.notenoughpets.util.FunctionsNEP;
import astrotibs.notenoughpets.util.Reference;
import astrotibs.notenoughpets.util.SkinVariations;
import net.minecraft.block.Block;
import net.minecraft.block.BlockJukebox;
import net.minecraft.block.BlockLeaves;
import net.minecraft.block.BlockLog;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAIMate;
import net.minecraft.entity.ai.EntityAIPanic;
import net.minecraft.entity.ai.EntityAISit;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.init.MobEffects;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumHand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.World;
import net.minecraft.world.storage.loot.LootTableList;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

/**
 * This is called EntityAIFollow in 1.12.2 but is only used for parrots
 */
public class EntityParrotNEP extends EntityShoulderRiding implements EntityFlying
{
	public static double rJB = Math.sqrt(12D); // Radius up to which a parrot responds to an active jukebox
	public static final ResourceLocation ENTITIES_PARROT = LootTableList.register(new ResourceLocation("minecraft", "entities/parrot"));

    private static final DataParameter<Integer> VARIANT = EntityDataManager.<Integer>createKey(EntityParrotNEP.class, DataSerializers.VARINT);
    // Added this so that we can scale the behbeh
    private static final DataParameter<Integer> NEC_AGE = EntityDataManager.<Integer>createKey(EntityParrotNEP.class, DataSerializers.VARINT);
    // Pasted in from 1.10's Entity class
    private static final DataParameter<Boolean> NO_GRAVITY = EntityDataManager.<Boolean>createKey(EntityParrotNEP.class, DataSerializers.BOOLEAN);

    /** Used to select entities the parrot can mimic the sound of */
    private static final Predicate<EntityLiving> CAN_MIMIC = new Predicate<EntityLiving>()
    {
        public boolean apply(@Nullable EntityLiving entityLiving)
        {
            return entityLiving != null && EntityParrotNEP.MIMIC_SOUNDS.containsKey(entityLiving.getClass().toString().substring(6));
        }
    };
    // Pasted in from 1.12 EntityLivingBase
    public static final net.minecraft.entity.ai.attributes.IAttribute SWIM_SPEED = new net.minecraft.entity.ai.attributes.RangedAttribute(null, "forge.swimSpeed", 1.0D, 0.0D, 1024.0D).setShouldWatch(true);
    private static final Item DEADLY_ITEM = Items.COOKIE;
    private static final java.util.Map<String, Object[]> MIMIC_SOUNDS = Maps.newHashMapWithExpectedSize(32);
    public float flap;
    public float flapSpeed;
    public float oFlapSpeed;
    public float oFlap;
    public float flapping = 1.0F;
    private boolean partyParrot;
    private BlockPos jukeboxPosition;
    private float nextFlap;
    public float moveVertical;
    public double flyingSpeed;

    public EntityParrotNEP(World worldIn)
    {
        super(worldIn);
        this.setSize(0.5F, 0.9F);
        this.moveHelper = new EntityFlyHelper(this);
        this.nextFlap = 1.0F;

        EntityAIFollowOwnerNEP.removeVanillaFollow(this);
		if (GeneralConfig.followOwnerParrot) {this.tasks.addTask(2, new EntityAIFollowOwnerFlying(this, 1.0D, 5.0F, 1.0F));}
    }

    public void setMoveVertical(float amount)
    {
        this.moveVertical = amount;
    }

    public float getMoveVertical()
    {
    	return this.moveVertical;
    }

    /**
     * Called only once on an entity when first time spawned, via egg, mob spawner, natural spawning etc, but not called
     * when entity is reloaded from nbt. Mainly used for initializing attributes and inventory
     */
    @Nullable
    @Override
    public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, @Nullable IEntityLivingData livingdata)
    {
        this.setVariant(this.rand.nextInt(SkinVariations.parrotSkinArray.length));
        return super.onInitialSpawn(difficulty, livingdata);
    }

    @Override
    protected void initEntityAI()
    {
        this.aiSit = new EntityAISit(this);
        this.tasks.addTask(0, new EntityAIPanic(this, 1.25D));
        this.tasks.addTask(0, new EntityAISwimmingNEP(this));
        this.tasks.addTask(1, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
        this.tasks.addTask(2, this.aiSit);
        //this.tasks.addTask(2, new EntityAIFollowOwnerFlying(this, 1.0D, 5.0F, 1.0F));
        this.tasks.addTask(2, new EntityAIMate(this, 0.8D));
        this.tasks.addTask(2, new EntityAIWanderAvoidWaterFlying(this, 1.0D));
        this.tasks.addTask(3, new EntityAILandOnOwnersShoulder(this));
        this.tasks.addTask(3, new EntityAIFollowParrot(this, 1.0D, 3.0F, 7.0F));
    }

    @Override
    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();

        //this.getAttributeMap().registerAttribute(SharedMonsterAttributes.FLYING_SPEED);
        this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(6.0D);

        //this.getEntityAttribute(SharedMonsterAttributes.FLYING_SPEED).setBaseValue(0.4000000059604645D);
        //IFlyingMovement ifm = (this).getCapability(FlyingMovementProvider.FLYING_MOVEMENT, null);
        //ifm.setFlyingSpeed(0.4000000059604645D);

        this.flyingSpeed = 0.4000000059604645D;
        this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.20000000298023224D);
        this.getAttributeMap().registerAttribute(SWIM_SPEED);
    }

    /**
     * Returns new PathNavigateGround instance
     */
    @Override
    protected PathNavigate getNewNavigator(World worldIn)
    {
        PathNavigateFlying pathnavigateflying = new PathNavigateFlying(this, worldIn);
        pathnavigateflying.setCanBreakDoors(false);
        pathnavigateflying.setCanFloat(true);
        pathnavigateflying.setCanEnterDoors(true);
        return pathnavigateflying;
    }

    @Override
    public float getEyeHeight()
    {
        return this.height * 0.6F;
    }

    /**
     * Method written to explicitly check whether there's a jukebox playing music nearby.
     */
    public BlockPos isJukeboxPlayingNearby(double radius)
    {
    	double rJBsqrd = radius*radius;
    	// Systematically check all blocks within a squared distance less than 12 (distance less than 3.46)
        for (int xScan = MathHelper.ceiling_double_int(this.posX-radius); xScan <= MathHelper.floor_double(this.posX+radius); xScan++) {

        	double yzCircleDist = xScan-this.posX; // current search plane's distance from the parrot in the x direction

        	for (int yScan = MathHelper.ceiling_double_int(this.posY-Math.sqrt(rJBsqrd-yzCircleDist*yzCircleDist)); yScan <= MathHelper.floor_double(this.posY+Math.sqrt(rJBsqrd-yzCircleDist*yzCircleDist)); yScan++) {

        		double zSliceDist = yScan-this.posY; // Current search row's distance from the parrot in the y direction

        		for (int zScan = MathHelper.ceiling_double_int(this.posZ-Math.sqrt(rJBsqrd-yzCircleDist*yzCircleDist-zSliceDist*zSliceDist)); zScan <= MathHelper.floor_double(this.posZ+Math.sqrt(rJBsqrd-yzCircleDist*yzCircleDist-zSliceDist*zSliceDist)); zScan++)
        		{
        			BlockPos pos = new BlockPos(xScan, yScan, zScan);
        			IBlockState iblockstate = this.worldObj.getBlockState(pos);
        			Block block = iblockstate.getBlock();

        			if (
        					block instanceof BlockJukebox
        					&& block.getMetaFromState(iblockstate)!=0
        					)
        			{
        				return new BlockPos(xScan, yScan, zScan);
        			}
        		}
        	}
        }
        return null;
    }

    /**
     * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
     * use this to react to sunlight and start to burn.
     */
    @Override
    public void onLivingUpdate()
    {
    	if (this.worldObj.rand.nextInt(100) < GeneralConfig.soundOccurrenceParrotAmbient) {playMimicSound(this.worldObj, this, this.getGrowingAge());}

        this.jukeboxPosition = isJukeboxPlayingNearby(rJB);

        if (this.jukeboxPosition == null || this.jukeboxPosition.distanceSq(this.posX, this.posY, this.posZ) > 12.0D || this.worldObj.getBlockState(this.jukeboxPosition).getBlock() != Blocks.JUKEBOX)
        {
            this.partyParrot = false;
            this.jukeboxPosition = null;
        }
        else
        {
        	this.partyParrot = true;
        }

        super.onLivingUpdate();

        //IFlyingMovement ifm = (this).getCapability(FlyingMovementProvider.FLYING_MOVEMENT, null);

        //this.travel(this.moveStrafing, this.getMoveVertical(), this.moveForward);
        this.calculateFlapping();
    }

    @SideOnly(Side.CLIENT)
    public void setPartying(BlockPos pos, boolean p_191987_2_)
    {
        this.jukeboxPosition = pos;
        this.partyParrot = p_191987_2_;
    }

    @SideOnly(Side.CLIENT)
    public boolean isPartying()
    {
        return this.partyParrot;
    }

    private void calculateFlapping()
    {
        this.oFlap = this.flap;
        this.oFlapSpeed = this.flapSpeed;
        this.flapSpeed = (float)((double)this.flapSpeed + (double)(this.onGround ? -1 : 4) * 0.3D);
        this.flapSpeed = MathHelper.clamp_float(this.flapSpeed, 0.0F, 1.0F);

        if (!this.onGround && this.flapping < 1.0F)
        {
            this.flapping = 1.0F;
        }

        this.flapping = (float)((double)this.flapping * 0.9D);

        if (!this.onGround && this.motionY < 0.0D)
        {
            this.motionY *= 0.6D;
        }

        this.flap += this.flapping * 2.0F;
    }

    private static boolean playMimicSound(World worldIn, Entity mimic, int entityAge)
    {
        if (!mimic.isSilent() && GeneralConfig.enableParrotMimicry && worldIn.rand.nextInt(100 * 50) < GeneralConfig.soundOccurrenceParrotImitate)
        {
            List<EntityLiving> list = worldIn.<EntityLiving>getEntitiesWithinAABB(EntityLiving.class, mimic.getEntityBoundingBox().expandXyz(20.0D), CAN_MIMIC);

            if (!list.isEmpty())
            {
                EntityLiving entityliving = list.get(worldIn.rand.nextInt(list.size()));

                if (!entityliving.isSilent())
                {
                	Object[] soundMimicObject = MIMIC_SOUNDS.get(entityliving.getClass().toString().substring(6));

                	SoundEvent soundevent = new SoundEvent(new ResourceLocation((String)soundMimicObject[0]));
                	float pitchMimic = (Float) soundMimicObject[1];

                    worldIn.playSound((EntityPlayer)null, mimic.posX, mimic.posY, mimic.posZ, soundevent, mimic.getSoundCategory(), 0.7F, getPitch(worldIn.rand)*pitchMimic*ageScalePitch(entityAge));
                    return true;
                }
            }
            return false;
        }
        else
        {
            return false;
        }
    }

	// Added manually to check against
	public static boolean isHealingFood(ItemStack itemstack)
	{
		return FunctionsNEP.isItemStackOnList(itemstack, GeneralConfig.parrotBreedingItem_a);
	}

    @Override
    public boolean processInteract(EntityPlayer player, EnumHand hand, ItemStack itemstack)
    {
    	// Attempt to tame
        if (!this.isTamed()
        		&& itemstack!=null
        		&& isHealingFood(itemstack))
        {
            if (!player.capabilities.isCreativeMode) {--itemstack.stackSize;}

            if (!this.isSilent())
            {
            	this.worldObj.playSound(
                		(EntityPlayer)null, this.posX, this.posY, this.posZ,
                		Reference.ENTITY_PARROT_EAT, this.getSoundCategory(),
                		1.0F, (1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F) * ageScalePitch(this.getGrowingAge())
                		);
            }

            if (!this.worldObj.isRemote)
            {
                if (this.rand.nextInt(10) == 0)
                {
                    this.setTamedBy(player);
                    this.playTameEffect(true);
                    this.worldObj.setEntityState(this, (byte)7);
                }
                else
                {
                    this.playTameEffect(false);
                    this.worldObj.setEntityState(this, (byte)6);
                }
            }

            return true;
        }
    	// Heal the little ingrate much seed very yum SQUOK
        else if (this.isTamed()
        		&& itemstack!=null
        		&& isHealingFood(itemstack) && this.getHealth() < this.getMaxHealth()
        		&& GeneralConfig.healingFoodParrot
        		)
        {
    		if (!player.capabilities.isCreativeMode) {--itemstack.stackSize;}
        	if (!this.isSilent())
        	{
        		this.worldObj.playSound(
                		(EntityPlayer)null, this.posX, this.posY, this.posZ,
                		Reference.ENTITY_PARROT_EAT, this.getSoundCategory(),
                		1.0F, (1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F)*ageScalePitch(this.getGrowingAge())
                		);
        	}

        	if (itemstack.getItem() instanceof ItemFood)
        	{
        		ItemFood itemfood = (ItemFood)itemstack.getItem();
        		this.heal((float)itemfood.getHealAmount(itemstack));
        	}
        	else
        	{
        		this.heal(GeneralConfig.parrotFeedingItemsDefaultAmount);
        	}

			this.playTameEffect(true); // True is hearts

			return true;
        }
		// Kill with cookie
        else if (itemstack!=null && itemstack.getItem() == DEADLY_ITEM)
        {
            if (!player.capabilities.isCreativeMode) {--itemstack.stackSize;}

            this.addPotionEffect(new PotionEffect(MobEffects.POISON, 900));

            boolean invulnerable_reflected = ReflectionHelper.getPrivateValue(Entity.class, this, new String[]{"invulnerable", "field_83001_bt"}); // The MCP mapping for this field name

            if ((player.isCreative() || !invulnerable_reflected) && GeneralConfig.cookiesKillParrots)
            {
                this.attackEntityFrom(DamageSource.causePlayerDamage(player), Float.MAX_VALUE);
            }

            return true;
        }
        // Play generic eating sound with food
    	if ((itemstack!=null
        		&& this.isBreedingItem(itemstack))
    			&& ((this.isOwner(player) && this.getGrowingAge() == 0 && !this.isInLove())
    					|| (this.isChild()))
    			)
        {
    		if (!this.isSilent()) {this.worldObj.playSound((EntityPlayer)null, this.posX, this.posY, this.posZ, Reference.ENTITY_PARROT_EAT, this.getSoundCategory(), 1.0F, (1.0F + (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F)*ageScalePitch(this.getGrowingAge()));}

    		return super.processInteract(player, hand, itemstack);
        }
        if (!this.worldObj.isRemote && !this.isFlying() && this.isTamed() && this.isOwner(player))
        {
            this.aiSit.setSitting(!this.isSitting());
        }

        // Proceed to super
        return super.processInteract(player, hand, itemstack);
    }

    public void setTamedBy(EntityPlayer player)
    {
        this.setTamed(true);
        this.setOwnerId(player.getUniqueID());
    }

    /**
     * Checks if the parameter is an item which this animal can be fed to breed it (wheat, carrots or seeds depending on
     * the animal type)
     */
    @Override
    public boolean isBreedingItem(ItemStack stack)
    {
    	return isHealingFood(stack); // Allows parrot to breed!
    }

    /**
     * Checks if the entity's current position is a valid location to spawn this entity.
     */
    @Override
    public boolean getCanSpawnHere()
    {
        int i = MathHelper.floor_double(this.posX);
        int j = MathHelper.floor_double(this.getEntityBoundingBox().minY);
        int k = MathHelper.floor_double(this.posZ);
        BlockPos blockpos = new BlockPos(i, j, k);
        Block block = this.worldObj.getBlockState(blockpos.down()).getBlock();
        return block instanceof BlockLeaves || block == Blocks.GRASS || block instanceof BlockLog || block == Blocks.AIR && this.worldObj.getLight(blockpos) > 8 && super.getCanSpawnHere();
    }

    @Override
    public void fall(float distance, float damageMultiplier)
    {
    }

    @Override
    protected void updateFallState(double y, boolean onGroundIn, IBlockState state, BlockPos pos)
    {
    }

    /**
     * Returns true if the mob is currently able to mate with the specified mob.
     */
    @Override
    public boolean canMateWith(EntityAnimal otherAnimal)
    {
        if (otherAnimal == this)
        {
            return false;
        }
        else if (!this.isTamed())
        {
            return false;
        }
        else if (!(otherAnimal instanceof EntityParrotNEP))
        {
            return false;
        }
        else
        {
        	EntityParrotNEP otherParrot = (EntityParrotNEP)otherAnimal;

            if (!otherParrot.isTamed())
            {
                return false;
            }
            else
            {
                return this.isInLove() && otherParrot.isInLove();
            }
        }
    }

    @Nullable
    @Override
    public EntityAgeable createChild(EntityAgeable otherParent)
    {
		EntityParrotNEP babyParrot = new EntityParrotNEP(this.worldObj);

        if (this.isTamed())
        {
            babyParrot.setOwnerId(this.getOwnerId());
            babyParrot.setTamed(true);
            // Set the offspring to a random variant based on the parents
            try
            {
            	babyParrot.setVariant( this.worldObj.rand.nextBoolean() ? this.getVariant() : ((EntityParrotNEP)otherParent).getVariant() );
            }
            catch (Exception e) {babyParrot.setVariant(this.getVariant());} // If something goes wrong, set the variant to this parrot
            // Randomly select a skin that has nothing to do with the parents - MUTATION!
            if (this.worldObj.rand.nextInt(1000)==0) {babyParrot.setVariant(SkinVariations.parrotSkinArray.length);}
        }
        return babyParrot;
    }

    /*
     * This is intended to be played when the parrot is on your shoulder
     */
    public static void playAmbientSound(World worldIn, Entity entity, int entityAge)
    {
		if (!entity.isSilent())
		{
			if (worldIn.rand.nextInt(100) < GeneralConfig.soundOccurrenceParrotAmbient)
	    	{
	    		if (!playMimicSound(worldIn, entity, entityAge) && worldIn.rand.nextInt(200) == 0)
		        {
	    			worldIn.playSound((EntityPlayer)null, entity.posX, entity.posY, entity.posZ, getAmbientSound(worldIn.rand), entity.getSoundCategory(), 1.0F, getPitch(worldIn.rand) * ageScalePitch(entityAge));
		        }
	    	}
		}
    }

    /**
     * Scales the parrot's pitch
     */
    public static float ageScalePitch(int age)
    {
    	return MathHelper.clamp_float(1.0F + 0.5F*(((float)age)/-24000), 1.0F, 1.5F);
    }

    @Override
    public boolean attackEntityAsMob(Entity entityIn)
    {
        return entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), 3.0F);
    }

    @Nullable
    @Override
    public SoundEvent getAmbientSound()
    {
		if (!this.isTamed() || rand.nextInt(100) < GeneralConfig.soundOccurrenceParrotAmbient)
		{
			return getAmbientSound(this.rand);
		}
		else
		{
			return null;
		}
    }

    private static SoundEvent getAmbientSound(Random random)
    {
        if (random.nextInt(100 * 1000) < GeneralConfig.soundOccurrenceParrotImitate)
        {
        	// Play a random sound from the mimic list
            List<Object[]> list = new ArrayList<Object[]>(MIMIC_SOUNDS.values());
            SoundEvent ret = new SoundEvent(new ResourceLocation((String)list.get(random.nextInt(list.size()))[0]));
            return ret == null ? Reference.ENTITY_PARROT_AMBIENT : ret;
        }
        else
        {
        	return Reference.ENTITY_PARROT_AMBIENT;
        }
    }

    @Override
    protected SoundEvent getHurtSound() // 1.12 takes the damage source as a parameter
    {
        return Reference.ENTITY_PARROT_HURT;
    }

    @Override
    protected SoundEvent getDeathSound()
    {
        return Reference.ENTITY_PARROT_DEATH;
    }

    @Override
    protected void playStepSound(BlockPos pos, Block blockIn)
    {
        this.playSound(Reference.ENTITY_PARROT_STEP, 0.15F, 1.0F);
    }

    @Override
    public void moveEntity(double x, double y, double z)
    {
    	super.moveEntity(x, y, z);

    	// The below was adapted from the move() method in Entity.class from 1.12.2
    	if (!this.noClip)
    	{
			int nextStepDistance_reflected = ReflectionHelper.getPrivateValue(Entity.class, this, new String[]{"nextStepDistance", "field_70150_b"}); // The MCP mapping for this field name

			IBlockState iblockstate = this.worldObj.getBlockState(new BlockPos(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY - 0.20000000298023224D), MathHelper.floor_double(this.posZ)));

    		if (
    				(this.canTriggerWalking() && !this.isRiding())
    				&& !(this.distanceWalkedOnStepModified > nextStepDistance_reflected && iblockstate.getMaterial() != Material.AIR)
    				&& (this.distanceWalkedOnStepModified > this.nextFlap && this.makeFlySound() && iblockstate.getMaterial() == Material.AIR)
    				)
            {
                this.nextFlap = this.playFlySound(this.distanceWalkedOnStepModified);
            }
    	}
    }

    protected float playFlySound(float distanceWalkedOnStepModified)
    {
        this.playSound(Reference.ENTITY_PARROT_FLY, 0.15F, 1.0F);
        return distanceWalkedOnStepModified + this.flapSpeed / 2.0F;
    }

    protected boolean makeFlySound()
    {
        return true;
    }

    /**
     * Gets the pitch of living sounds in living entities.
     */
    @Override
    protected float getSoundPitch()
    {
        //return getPitch(this.rand);
    	return FunctionsNEP.getScaledSoundPitch(this);
    }

    private static float getPitch(Random random)
    {
        return (random.nextFloat() - random.nextFloat()) * 0.2F + 1.0F;
    }

    @Override
    public SoundCategory getSoundCategory()
    {
        return SoundCategory.NEUTRAL;
    }

    /**
     * Returns true if this entity should push and be pushed by other entities when colliding.
     */
    @Override
    public boolean canBePushed()
    {
        return true;
    }

    @Override
    protected void collideWithEntity(Entity entityIn)
    {
        if (!(entityIn instanceof EntityPlayer))
        {
            super.collideWithEntity(entityIn);
        }
    }

    /**
     * Called when the entity is attacked.
     */
    @Override
    public boolean attackEntityFrom(DamageSource source, float amount)
    {
        if (this.isEntityInvulnerable(source))
        {
            return false;
        }
        else
        {
            if (this.aiSit != null)
            {
                this.aiSit.setSitting(false);
            }

            return super.attackEntityFrom(source, amount);
        }
    }

    public int getVariant()
    {
        return ((Integer)this.dataManager.get(VARIANT)).intValue() % SkinVariations.parrotSkinArray.length;
    }

    public void setVariant(int variant)
    {
        this.dataManager.set(VARIANT, Integer.valueOf(variant));
    }

    @Override
    protected void entityInit()
    {
        super.entityInit();
        this.dataManager.register(VARIANT, Integer.valueOf(0));
        // For baby scaling
        this.dataManager.register(NEC_AGE, Integer.valueOf(0));
        // Added in because 1.9 has no NO_GRAVITY flag
        this.dataManager.register(NO_GRAVITY, Boolean.valueOf(false));
    }

    // Pasted in from 1.10's Entity class
    public boolean hasNoGravity() {return ((Boolean)this.dataManager.get(NO_GRAVITY)).booleanValue();}
    public void setNoGravity(boolean noGravity) {this.dataManager.set(NO_GRAVITY, Boolean.valueOf(noGravity));}

	@Override
    public int getGrowingAge()
    {
		return this.dataManager.get(NEC_AGE);
    }

	// Added in v1.2.1
	@Override
    public void setGrowingAge(int age)
    {
		super.setGrowingAge(age);
		this.dataManager.set(NEC_AGE, age);
    }

    /**
     * (abstract) Protected helper method to write subclass entity data to NBT.
     */
    @Override
    public void writeEntityToNBT(NBTTagCompound compound)
    {
        super.writeEntityToNBT(compound);
        compound.setInteger("Variant", this.getVariant());
    }

    /**
     * (abstract) Protected helper method to read subclass entity data from NBT.
     */
    @Override
    public void readEntityFromNBT(NBTTagCompound compound)
    {
        super.readEntityFromNBT(compound);
        this.setVariant(compound.getInteger("Variant"));
    }

    @Nullable
    protected ResourceLocation getLootTable()
    {
    	return ENTITIES_PARROT; //LootTableList.ENTITIES_PARROT;
    }

    public boolean isFlying()
    {
        return !this.onGround;
    }

    // Register all the mimic sounds in the config
    static
    {
    	registerMimicsFromConfig(GeneralConfig.parrotMimicSounds);
    }

	/**
	 * Loads the (classPath|soundPath|pitch) string lists and assigns them to this instance's variables.
	 */
	public static void registerMimicsFromConfig(String[] inputList)
	{
		for (String entry : inputList)
		{
			// Split by pipe
			String[] splitEntry = entry.split("\\|");
			try
			{
				registerMimicSound(splitEntry[0].trim(), splitEntry[1].trim(), Float.parseFloat(splitEntry[2].trim()));
			}
			catch (Exception e) {} // Failed to interpret config entry
		}

		// Load the defaults if there is a problem
		if (MIMIC_SOUNDS.size() == 0)
		{
	    	registerMimicSound("net.minecraft.entity.monster.EntityBlaze",           Reference.MOD_ID+":entity.parrot.imitate.blaze", 1.8F);
	        registerMimicSound("net.minecraft.entity.monster.EntityCaveSpider",      Reference.MOD_ID+":entity.parrot.imitate.spider", 1.8F);
	        registerMimicSound("net.minecraft.entity.monster.EntityCreeper",         Reference.MOD_ID+":entity.parrot.imitate.creeper", 1.8F);
	        //registerMimicSound("net.minecraft.entity.monster.EntityElderGuardian",   Reference.MOD_ID+":entity.parrot.imitate.elder_guardian", 1.8F); // Added in 1.11
	        registerMimicSound("net.minecraft.entity.boss.EntityDragon",          Reference.MOD_ID+":entity.parrot.imitate.enderdragon", 1.8F);
	        registerMimicSound("net.minecraft.entity.monster.EntityEnderman",        Reference.MOD_ID+":entity.parrot.imitate.enderman", 1.7F);
	        registerMimicSound("net.minecraft.entity.monster.EntityEndermite",       Reference.MOD_ID+":entity.parrot.imitate.endermite", 1.8F);
	        //registerMimicSound("net.minecraft.entity.monster.EntityEvoker",          Reference.MOD_ID+":entity.parrot.imitate.evocation_illager", 1.8F); // Added in 1.11
	        registerMimicSound("net.minecraft.entity.monster.EntityGhast",           Reference.MOD_ID+":entity.parrot.imitate.ghast", 1.8F);
	        //registerMimicSound("net.minecraft.entity.monster.EntityHusk",            Reference.MOD_ID+":entity.parrot.imitate.husk", 1.8F); // Added in 1.11
	        //registerMimicSound("net.minecraft.entity.monster.EntityIllusionIllager", Reference.MOD_ID+":entity.parrot.imitate.illusion_illager", 1.8F); // Added in 1.12
	        registerMimicSound("net.minecraft.entity.monster.EntityMagmaCube",       Reference.MOD_ID+":entity.parrot.imitate.magmacube", 1.8F);
	        registerMimicSound("net.minecraft.entity.monster.EntityPigZombie",       Reference.MOD_ID+":entity.parrot.imitate.zombie_pigman", 1.8F);
	        //registerMimicSound("net.minecraft.entity.monster.EntityPolarBear",       Reference.MOD_ID+":entity.parrot.imitate.polar_bear", 0.7F); // Added in 1.10
	        registerMimicSound("net.minecraft.entity.monster.EntityShulker",         Reference.MOD_ID+":entity.parrot.imitate.shulker", 1.7F);
	        registerMimicSound("net.minecraft.entity.monster.EntitySilverfish",      Reference.MOD_ID+":entity.parrot.imitate.silverfish", 1.8F);
	        registerMimicSound("net.minecraft.entity.monster.EntitySkeleton",        Reference.MOD_ID+":entity.parrot.imitate.skeleton", 1.7F);
	        registerMimicSound("net.minecraft.entity.monster.EntitySlime",           Reference.MOD_ID+":entity.parrot.imitate.slime", 1.8F);
	        registerMimicSound("net.minecraft.entity.monster.EntitySpider",          Reference.MOD_ID+":entity.parrot.imitate.spider", 1.8F);
	        //registerMimicSound("net.minecraft.entity.monster.EntityStray",           Reference.MOD_ID+":entity.parrot.imitate.stray", 1.6F); // Added in 1.11
	        //registerMimicSound("net.minecraft.entity.monster.EntityVex",             Reference.MOD_ID+":entity.parrot.imitate.vex", 1.6F); // Added in 1.11
	        //registerMimicSound("net.minecraft.entity.monster.EntityVindicator",      Reference.MOD_ID+":entity.parrot.imitate.vindication_illager", 1.7F); // Added in 1.11
	        registerMimicSound("net.minecraft.entity.monster.EntityWitch",           Reference.MOD_ID+":entity.parrot.imitate.witch", 1.8F);
	        registerMimicSound("net.minecraft.entity.boss.EntityWither",          Reference.MOD_ID+":entity.parrot.imitate.wither", 1.8F);
	        //registerMimicSound("net.minecraft.entity.monster.EntityWitherSkeleton",  Reference.MOD_ID+":entity.parrot.imitate.wither_skeleton", 1.8F); // Added in 1.11
	        //registerMimicSound("net.minecraft.entity.passive.EntityWolf",            Reference.MOD_ID+":entity.parrot.imitate.wolf", 1.8F);
	        registerMimicSound("net.minecraft.entity.monster.EntityZombie",          Reference.MOD_ID+":entity.parrot.imitate.zombie", 1.8F);
	        //registerMimicSound("net.minecraft.entity.monster.EntityZombieVillager",  Reference.MOD_ID+":entity.parrot.imitate.zombie_villager", 1.8F); // Added in 1.11
		}
	}

    public static void registerMimicSound(String classpath, String sound, float pitch)
    {
    	pitch = MathHelper.clamp_float(pitch, 0.4F, 2.0F);
        MIMIC_SOUNDS.put(classpath, new Object[]{sound, pitch});
    }

    // Pasted in from EntityLivingBase in 1.10
    protected float getWaterSlowDown() {return 0.8F;}

    /**
     * Copied out of 1.12 because moveEntityWithHeading() was changed to travel() and now includes a vertical component
     * It's going to attempt to use this entity's vertical motion value to substitute for the input parameter
     */
    @Override
    public void moveEntityWithHeading(float strafe, float forward)
    {
        if (this.isServerWorld() || this.canPassengerSteer())
        {
            if (!this.isInWater())// || this instanceof EntityPlayer && ((EntityPlayer)this).capabilities.isFlying)
            {
                if (!this.isInLava())// || this instanceof EntityPlayer && ((EntityPlayer)this).capabilities.isFlying)
                {
                	// Movement in air

                    if (this.isElytraFlying())
                    {
                        if (this.motionY > -0.5D)
                        {
                            this.fallDistance = 1.0F;
                        }

                        Vec3d vec3d = this.getLookVec();
                        float f = this.rotationPitch * 0.017453292F;
                        double d6 = Math.sqrt(vec3d.xCoord * vec3d.xCoord + vec3d.zCoord * vec3d.zCoord);
                        double d8 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
                        double d1 = vec3d.lengthVector();
                        float f4 = MathHelper.cos(f);
                        f4 = (float)((double)f4 * (double)f4 * Math.min(1.0D, d1 / 0.4D));
                        this.motionY += -0.08D + (double)f4 * 0.06D;

                        if (this.motionY < 0.0D && d6 > 0.0D)
                        {
                            double d2 = this.motionY * -0.1D * (double)f4;
                            this.motionY += d2;
                            this.motionX += vec3d.xCoord * d2 / d6;
                            this.motionZ += vec3d.zCoord * d2 / d6;
                        }

                        if (f < 0.0F)
                        {
                            double d10 = d8 * (double)(-MathHelper.sin(f)) * 0.04D;
                            this.motionY += d10 * 3.2D;
                            this.motionX -= vec3d.xCoord * d10 / d6;
                            this.motionZ -= vec3d.zCoord * d10 / d6;
                        }

                        if (d6 > 0.0D)
                        {
                            this.motionX += (vec3d.xCoord / d6 * d8 - this.motionX) * 0.1D;
                            this.motionZ += (vec3d.zCoord / d6 * d8 - this.motionZ) * 0.1D;
                        }

                        this.motionX *= 0.9900000095367432D;
                        this.motionY *= 0.9800000190734863D;
                        this.motionZ *= 0.9900000095367432D;
                        this.moveEntity(this.motionX, this.motionY, this.motionZ);

                        if (this.isCollidedHorizontally && !this.worldObj.isRemote)
                        {
                            double d11 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
                            double d3 = d8 - d11;
                            float f5 = (float)(d3 * 10.0D - 3.0D);

                            if (f5 > 0.0F)
                            {
                                this.playSound(this.getFallSound((int)f5), 1.0F, 1.0F);
                                this.attackEntityFrom(DamageSource.flyIntoWall, f5);
                            }
                        }

                        if (this.onGround && !this.worldObj.isRemote)
                        {
                            this.setFlag(7, false);
                        }
                    }
                    else
                    {
                        float f6 = 0.91F;
                        BlockPos.PooledMutableBlockPos blockpos$pooledmutableblockpos = BlockPos.PooledMutableBlockPos.retain(this.posX, this.getEntityBoundingBox().minY - 1.0D, this.posZ);

                        if (this.onGround)
                        {
                            IBlockState underState = this.worldObj.getBlockState(blockpos$pooledmutableblockpos);
                            //f6 = underState.getBlock().getSlipperiness(underState, this.world, blockpos$pooledmutableblockpos, this) * 0.91F;
                            // Below is 1.11 version of slipperiness
                            f6 = this.worldObj.getBlockState(blockpos$pooledmutableblockpos.setPos(this.posX, this.getEntityBoundingBox().minY - 1.0D, this.posZ)).getBlock().slipperiness * 0.91F;
                        }

                        float f7 = 0.16277136F / (f6 * f6 * f6);
                        float f8;

                        if (this.onGround)
                        {
                            f8 = this.getAIMoveSpeed() * f7;
                        }
                        else
                        {
                            f8 = this.jumpMovementFactor;
                        }

                        this.moveRelative(strafe, this.getMoveVertical(), forward, f8);
                        f6 = 0.91F;

                        if (this.onGround)
                        {
                            IBlockState underState = this.worldObj.getBlockState(blockpos$pooledmutableblockpos.setPos(this.posX, this.getEntityBoundingBox().minY - 1.0D, this.posZ));
                            //f6 = underState.getBlock().getSlipperiness(underState, this.world, blockpos$pooledmutableblockpos, this) * 0.91F;
                            f6 = this.worldObj.getBlockState(blockpos$pooledmutableblockpos.setPos(this.posX, this.getEntityBoundingBox().minY - 1.0D, this.posZ)).getBlock().slipperiness * 0.91F;
                        }

                        if (this.isOnLadder())
                        {
                            float f9 = 0.15F;
                            this.motionX = MathHelper.clamp_double(this.motionX, -0.15000000596046448D, 0.15000000596046448D);
                            this.motionZ = MathHelper.clamp_double(this.motionZ, -0.15000000596046448D, 0.15000000596046448D);
                            this.fallDistance = 0.0F;

                            if (this.motionY < -0.15D)
                            {
                                this.motionY = -0.15D;
                            }

                            /*
                            boolean flag = false;//this.isSneaking() && this instanceof EntityPlayer;

                            if (flag && this.motionY < 0.0D)
                            {
                                this.motionY = 0.0D;
                            }*/
                        }

                        this.moveEntity(this.motionX, this.motionY, this.motionZ);

                        if (this.isCollidedHorizontally && this.isOnLadder())
                        {
                            this.motionY = 0.2D;
                        }

                        if (this.isPotionActive(MobEffects.LEVITATION))
                        {
                            this.motionY += (0.05D * (double)(this.getActivePotionEffect(MobEffects.LEVITATION).getAmplifier() + 1) - this.motionY) * 0.2D;
                        }
                        else
                        {
                            blockpos$pooledmutableblockpos.setPos(this.posX, 0.0D, this.posZ);

                            if (!this.worldObj.isRemote
                            		||
                            		this.worldObj.isBlockLoaded(blockpos$pooledmutableblockpos) && this.worldObj.getChunkFromBlockCoords(blockpos$pooledmutableblockpos).isLoaded()
                            		)
                            {
                                if (!this.hasNoGravity())
                                {
                                    this.motionY -= 0.08D;
                                }
                            }
                            else if (this.posY > 0.0D)
                            {
                                this.motionY = -0.1D;
                            }
                            else
                            {
                                this.motionY = 0.0D;
                            }
                        }

                        this.motionY *= 0.9800000190734863D;
                        this.motionX *= (double)f6;
                        this.motionZ *= (double)f6;
                        blockpos$pooledmutableblockpos.release();
                    }
                }
                else
                {
                	// Movement in lava

                    double d4 = this.posY;
                    this.moveRelative(strafe, this.getMoveVertical(), forward, 0.02F);
                    this.moveEntity(this.motionX, this.motionY, this.motionZ);
                    this.motionX *= 0.5D;
                    this.motionY *= 0.5D;
                    this.motionZ *= 0.5D;

                    if (!this.hasNoGravity())
                    {
                        this.motionY -= 0.02D;
                    }

                    if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + d4, this.motionZ))
                    {
                        this.motionY = 0.30000001192092896D;
                    }
                }
            }
            else
            {
            	// Movement in water

                double d0 = this.posY;
                float f1 = this.getWaterSlowDown();
                float f2 = 0.02F;
                float f3 = (float)EnchantmentHelper.getDepthStriderModifier(this);

                if (f3 > 3.0F)
                {
                    f3 = 3.0F;
                }

                if (!this.onGround)
                {
                    f3 *= 0.5F;
                }

                if (f3 > 0.0F)
                {
                    f1 += (0.54600006F - f1) * f3 / 3.0F;
                    f2 += (this.getAIMoveSpeed() - f2) * f3 / 3.0F;
                }

                this.moveRelative(strafe, this.getMoveVertical(), forward, f2);
                this.moveEntity(this.motionX, this.motionY, this.motionZ);
                this.motionX *= (double)f1;
                this.motionY *= 0.800000011920929D;
                this.motionZ *= (double)f1;

                if (!this.hasNoGravity())
                {
                    this.motionY -= 0.02D;
                }

                if (this.isCollidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + d0, this.motionZ))
                {
                    this.motionY = 0.30000001192092896D;
                }
            }
        }

        this.prevLimbSwingAmount = this.limbSwingAmount;
        double d5 = this.posX - this.prevPosX;
        double d7 = this.posZ - this.prevPosZ;
        double d9 = this instanceof EntityFlying ? this.posY - this.prevPosY : 0.0D;
        float f10 = MathHelper.sqrt_double(d5 * d5 + d9 * d9 + d7 * d7) * 4.0F;

        if (f10 > 1.0F)
        {
            f10 = 1.0F;
        }

        this.limbSwingAmount += (f10 - this.limbSwingAmount) * 0.4F;
        this.limbSwing += this.limbSwingAmount;
    }

    public void moveRelative(float strafe, float up, float forward, float friction)
    {
    	// I think setting these to zero undoes the additional speed introduced in the travel() method
        //forward = 0;
        //strafe = 0;

    	float f = strafe * strafe + up * up + forward * forward;

        if (f >= 1.0E-4F)
        {
            f = MathHelper.sqrt_float(f);

            if (f < 1.0F) {f = 1.0F;}

            f = friction / f;
            strafe = strafe * f;
            up = up * f;
            forward = forward * f;

            if(this.isInWater() || this.isInLava())
            {
                strafe = strafe * (float)this.getEntityAttribute(SWIM_SPEED).getAttributeValue();
                up = up * (float)this.getEntityAttribute(SWIM_SPEED).getAttributeValue();
                forward = forward * (float)this.getEntityAttribute(SWIM_SPEED).getAttributeValue();
            }
            float f1 = MathHelper.sin(this.rotationYaw * 0.017453292F);
            float f2 = MathHelper.cos(this.rotationYaw * 0.017453292F);
            this.motionX += (double)(strafe * f2 - forward * f1);
            this.motionY += (double)up;
            this.motionZ += (double)(forward * f2 + strafe * f1);
        }
    }

}

license: unknown


code:
package astrotibs.notenoughpets.entity;

import astrotibs.notenoughpets.capabilities.shoulderriding.IShoulderRiding;
import astrotibs.notenoughpets.capabilities.shoulderriding.ShoulderRidingProvider;
import net.minecraft.entity.passive.EntityTameable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;

public abstract class EntityShoulderRiding extends EntityTameable
{
    private int rideCooldownCounter;

    public EntityShoulderRiding(World world)
    {
        super(world);
    }

    public boolean setEntityOnShoulder(EntityPlayer player)
    {
        NBTTagCompound nbttagcompound = new NBTTagCompound();
        nbttagcompound.setString("id", this.getEntityString());
        this.writeToNBT(nbttagcompound);

        IShoulderRiding isr = player.getCapability(ShoulderRidingProvider.SHOULDER_RIDING, null);

        if (isr.addShoulderEntity(player, nbttagcompound))
        {
            this.worldObj.removeEntity(this);
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Called to update the entity's position/logic.
     */
    public void onUpdate()
    {
        ++this.rideCooldownCounter;
        super.onUpdate();
    }

    public boolean canSitOnShoulder()
    {
        return this.rideCooldownCounter > 100;
    }
}


code:
package astrotibs.notenoughpets.entity;

import javax.annotation.Nullable;

import astrotibs.notenoughpets.ai.EntityAIFollowOwnerNEP;
import astrotibs.notenoughpets.config.GeneralConfig;
import astrotibs.notenoughpets.util.FunctionsNEP;
import astrotibs.notenoughpets.util.Reference;
import astrotibs.notenoughpets.util.SkinVariations;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntitySheep;
import net.minecraft.entity.passive.EntityWolf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundEvent;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.ReflectionHelper;

public class EntityWolfNEP extends EntityWolf {

	private static final DataParameter<Integer> NEC_AGE = EntityDataManager.<Integer>createKey(EntityWolfNEP.class, DataSerializers.VARINT);

	public EntityWolfNEP(World world) {
		super(world);

		EntityAIFollowOwnerNEP.removeVanillaFollow(this);

		if (GeneralConfig.followOwnerDog) {this.tasks.addTask(5, new EntityAIFollowOwnerNEP(this, 1.0D, 10.0F, 2.0F));}
	}

	// Stray non-wolves don't attack sheep
	@Override
	public void setAttackTarget(@Nullable EntityLivingBase entitylivingbaseIn)
    {
		super.setAttackTarget(entitylivingbaseIn);

		if (this.getTameSkin() != 0 && !this.isTamed() && super.getAttackTarget() instanceof EntitySheep)
		{
			this.setAngry(false);
			super.setAttackTarget(null);
			return;
		}
    }

	@Override
	protected SoundEvent getAmbientSound()
	{
		// Suppression only applies to tamed
		if (!this.isTamed() || rand.nextInt(100) < GeneralConfig.soundOccurrenceDog)
		{
			// Pugs sometimes growl instead of panting
			if (this.getTameSkin()==7)
			{
				DataParameter<Float> DATA_HEALTH_ID_reflected = ReflectionHelper.getPrivateValue(EntityWolf.class, this, new String[]{"DATA_HEALTH_ID", "field_184759_bz"});

				return this.isAngry() ?
						SoundEvents.ENTITY_WOLF_GROWL :
							(this.rand.nextInt(3) == 0 ?
									(this.isTamed() && ((Float)this.dataManager.get(DATA_HEALTH_ID_reflected)).floatValue() < 10.0F ?
											SoundEvents.ENTITY_WOLF_WHINE :
												this.rand.nextBoolean() ? SoundEvents.ENTITY_WOLF_PANT : SoundEvents.ENTITY_WOLF_GROWL) :
													SoundEvents.ENTITY_WOLF_AMBIENT);
			}
			else
			{
				return super.getAmbientSound();
			}
		}
		else
		{
			return null;
		}
	}

	/**
     * Gets the pitch of living sounds in living entities.
     */
	@Override
    protected float getSoundPitch()
    {
		return FunctionsNEP.getScaledSoundPitch(this) + 0.7F*(1F/dogBreedScale(this)-1F); // Pitch up sounds for smaller breeds
    }

	// How to scale the dog's size based on its breed
    public static float dogBreedScale(EntityWolfNEP wolf)
    {
    	switch (wolf.getTameSkin())
    	{
    		case 7: // Pug
    			return 0.5F;
    		case 9: // Boston Terrier
    			return 0.6F;
    		case 4: // White Terrier
    			return 0.7F;
    		case 6: // Beagle
    			return 0.8F;
    		default:
    			return 1.0F;
    		case 11: // Golden Retriever
    			return 1.1F;
    		case 10: // St. Bernard
    			return 1.2F;
    	}
    }

    private static final DataParameter<Integer> WOLF_VARIANT = EntityDataManager.<Integer>createKey(EntityWolfNEP.class, DataSerializers.VARINT);

	@Override
	protected void entityInit()
	{
		super.entityInit();

        // A datawatcher value to represent type: for new skins
        this.dataManager.register(WOLF_VARIANT, Integer.valueOf(0));

        // A datawatcher value to represent age, because stupid 1.8+ culls it to a byte
    	//this.dataWatcher.addObject(21, new Integer(0));
		this.dataManager.register(NEC_AGE, Integer.valueOf(0));
	}

	@Override
    public int getGrowingAge()
    {
		return this.dataManager.get(NEC_AGE);
    }

	@Override
    public void setGrowingAge(int age)
    {
		super.setGrowingAge(age);
		this.dataManager.set(NEC_AGE, age);
    }

    public int getTameSkin()
    {
    	return ((Integer)this.dataManager.get(WOLF_VARIANT)).intValue();
    }

    public void setTameSkin(int skinId)
    {
    	this.dataManager.set(WOLF_VARIANT, Integer.valueOf(skinId));
    }

    @Override
    public void writeEntityToNBT(NBTTagCompound tagCompound)
    {
        super.writeEntityToNBT(tagCompound);
        tagCompound.setInteger("DogType", this.getTameSkin());
    }

    @Override
    public void readEntityFromNBT(NBTTagCompound tagCompund)
    {
        super.readEntityFromNBT(tagCompund);
        this.setTameSkin(tagCompund.getInteger("DogType"));
    }

    @Override
    public EntityWolfNEP createChild(EntityAgeable otherParent)
    {
    	EntityWolfNEP babyWolf = new EntityWolfNEP(this.worldObj);

        if (this.isTamed())
        {
            babyWolf.setOwnerId(this.getOwnerId());
            babyWolf.setTamed(true);
            // Set the offspring to a random variant based on the parents
            try
            {
            	babyWolf.setTameSkin( this.worldObj.rand.nextBoolean() ? this.getTameSkin() : ((EntityWolfNEP)otherParent).getTameSkin() );
            }
            catch (Exception e) {babyWolf.setTameSkin(this.getTameSkin());}
            // Randomly select a skin that has nothing to do with the parents - MUTATION!
            if (this.worldObj.rand.nextInt(1000)==0) {babyWolf.setTameSkin(SkinVariations.dogSkinArray.length);}
        }

        return babyWolf;
    }

    @Override
    public boolean processInteract(EntityPlayer player, EnumHand hand, @Nullable ItemStack itemstack)
    {
    	// Play a sound when you dye the wolf's collar
    	if (
    			this.isTamed()
    			&& itemstack!=null
    			)
        {
    		if (itemstack.getItem() == Items.DYE)
    		{
        		EnumDyeColor enumdyecolor = EnumDyeColor.byDyeDamage(itemstack.getMetadata());

    			if (enumdyecolor != this.getCollarColor())
                {
    				this.setCollarColor(enumdyecolor);
    				if (!player.capabilities.isCreativeMode) {--itemstack.stackSize;}
    				if (!this.isSilent()) {this.playSound(Reference.SE_DYE_COLLAR, this.getSoundVolume(), 1F);}

    				return true;
                }
    		}
    		else if (FunctionsNEP.isItemStackOnList(itemstack, GeneralConfig.dogBreedingItem_a))
    		{
    			// Heal the dog
    			if (this.isBreedingItem(itemstack) && (this.getHealth() < this.getMaxHealth()))
    			{
    				if (!player.capabilities.isCreativeMode) {--itemstack.stackSize;}
    				float healAmount = itemstack.getItem() instanceof ItemFood ? ((ItemFood)itemstack.getItem()).getHealAmount(itemstack) : GeneralConfig.dogFeedingItemsDefaultAmount;
    				this.heal(healAmount);

                    return true;
    			}
    		}
    		else if (itemstack.getItem() instanceof ItemFood && ((ItemFood)itemstack.getItem()).isWolfsFavoriteMeat())
    		{
    			// Item is a vanilla food for this animal but WASN'T on the config list
    			return false;
    		}
        }

    	return super.processInteract(player, hand, itemstack);
    }

    /**
     * Checks if the parameter is an item which this animal can be fed to breed it
     */
    @Override
    public boolean isBreedingItem(ItemStack itemStack)
    {
    	return itemStack == null ? false : FunctionsNEP.isItemStackOnList(itemStack, GeneralConfig.dogBreedingItem_a);
    }
}