package common.entity.npc;

import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.function.Predicate;

import common.ai.AIRangedAttack;
import common.ai.EntityAIAttackOnCollide;
import common.ai.EntityAIAvoidEntity;
import common.ai.EntityAIHurtByTarget;
import common.ai.EntityAILookAtTalkingPlayer;
import common.ai.EntityAINagPlayer;
import common.ai.EntityAINearestAttackableTarget;
import common.ai.EntityAINpcInteract;
import common.ai.EntityAINpcMate;
import common.ai.EntityAIOpenDoor;
import common.ai.EntityAIPlay;
import common.ai.EntityAISwimming;
import common.ai.EntityAIWander;
import common.ai.EntityAIWatchClosest;
import common.ai.EntityAIWatchClosest2;
import common.attributes.AttributeInstance;
import common.attributes.Attributes;
import common.block.Block;
import common.block.BlockBed;
import common.dimension.Space;
import common.enchantment.Enchantment;
import common.enchantment.EnchantmentHelper;
import common.entity.DamageSource;
import common.entity.Entity;
import common.entity.EntityType;
import common.entity.animal.EntityDragonPart;
import common.entity.animal.EntityHorse;
import common.entity.animal.EntityPig;
import common.entity.item.EntityBoat;
import common.entity.item.EntityCart;
import common.entity.item.EntityItem;
import common.entity.projectile.EntityArrow;
import common.entity.projectile.EntityBullet;
import common.entity.projectile.EntityHook;
import common.entity.projectile.EntityPotion;
import common.entity.projectile.EntitySnowball;
import common.entity.types.EntityLiving;
import common.entity.types.IEntityMultiPart;
import common.init.Config;
import common.init.ItemRegistry;
import common.init.Items;
import common.init.NameRegistry;
import common.init.SoundEvent;
import common.init.SpeciesRegistry;
import common.init.TradeRegistry;
import common.init.SpeciesRegistry.ModelType;
import common.inventory.Container;
import common.inventory.ContainerPlayer;
import common.inventory.IInventory;
import common.inventory.InventoryBasic;
import common.inventory.InventoryPlayer;
import common.inventory.InventoryWarpChest;
import common.item.Item;
import common.item.ItemAction;
import common.item.ItemArmor;
import common.item.ItemBow;
import common.item.ItemGunBase;
import common.item.ItemHoe;
import common.item.ItemShears;
import common.item.ItemStack;
import common.item.ItemSword;
import common.item.ItemTool;
import common.model.ParticleType;
import common.nbt.NBTTagCompound;
import common.nbt.NBTTagList;
import common.network.IClientPlayer;
import common.network.IPlayer;
import common.packet.CPacketAction;
import common.packet.CPacketBreak;
import common.packet.CPacketInput;
import common.packet.CPacketPlayer;
import common.packet.SPacketEntityEquipment;
import common.packet.SPacketEntityVelocity;
import common.pathfinding.PathNavigateGround;
import common.potion.Potion;
import common.potion.PotionEffect;
import common.rng.Random;
import common.sound.MovingSoundMinecartRiding;
import common.tileentity.IInteractionObject;
import common.tileentity.LockCode;
import common.tileentity.TileEntitySign;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.ExtMath;
import common.util.Facing;
import common.util.PortalType;
import common.util.Vec3;
import common.util.WorldPos;
import common.village.MerchantRecipeList;
import common.world.AWorldClient;
import common.world.World;
import common.world.AWorldServer;

public abstract class EntityNPC extends EntityLiving
{
	public static class CharacterTypeData
    {
        public final CharacterInfo character;

        public CharacterTypeData(CharacterInfo character)
        {
            this.character = character;
        }
    }
	
	public static class AlignmentData
    {
        public final Alignment alignment;

        public AlignmentData(Alignment alignment)
        {
            this.alignment = alignment;
        }
    }

	public static String getSkinTexture(String skin)
    {
    	return "textures/entity/" + skin + ".png";
    }
	
	public static String getCapeTexture(String cape)
    {
    	return "textures/entity/cape_" + cape + ".png";
    }
    
//    public static String getSpeciesName(String character) {
//    	return (character.substring(0, 1).toUpperCase() + character.substring(1)).replace('_', ' ').replaceAll("( [a-z])", "$1");
//    }
    
    protected final EntityAIAttackOnCollide aiMelee = new EntityAIAttackOnCollide(this, EntityLiving.class, 1.0D, true, true) {
    	public boolean shouldExecute()
        {
        	return !EntityNPC.this.fleeing && super.shouldExecute();
        }
    	
        public boolean continueExecuting()
        {
        	return !EntityNPC.this.fleeing && super.shouldExecute();
        }
    };
    protected final AIRangedAttack aiRanged = new AIRangedAttack(this, 1.0D, this.getAttackSpeed(), this.getAttackSpeed() * 3, 15.0F) {
//    	public void startExecuting()
//        {
//            super.startExecuting();
//            EntityNPC.this.setUsingItem(true);
//        }
//    	
//    	public void resetTask()
//        {
//            super.resetTask();
//            EntityNPC.this.setUsingItem(false);
//        }
    	
        public boolean shouldExecute()
        {
        	return !EntityNPC.this.fleeing && super.shouldExecute();
        }
    	
        public boolean continueExecuting()
        {
        	return !EntityNPC.this.fleeing && super.shouldExecute();
        }
    };

    protected final SpeciesInfo species;
    
    private EntityNPC talkingPlayer;
    private boolean isWilling;
    private boolean fleeing;
    private boolean playing;
    protected boolean noPickup;
	private ItemStack[] equipment = new ItemStack[5];
    private final ItemStack[] prevEquipment = new ItemStack[5];
    private InventoryBasic extraInventory;
    private int inLove;
    protected Alignment alignment = Alignment.NEUTRAL;
	private MerchantRecipeList trades;
    private int healTimer;
    private byte[] skin;

	public IPlayer connection;
    public IClientPlayer client;
    protected boolean slave;
	
    public InventoryPlayer inventory;
    protected InventoryWarpChest warpChest;
    public ContainerPlayer inventoryContainer;
    public Container openContainer;
    public boolean flying;
    public boolean noclip;
    protected int flyToggleTimer;
    public float prevCameraYaw;
    public float cameraYaw;
    public int xpCooldown;
    public double prevChasingPosX;
    public double prevChasingPosY;
    public double prevChasingPosZ;
    public double chasingPosX;
    public double chasingPosY;
    public double chasingPosZ;
    private WorldPos originPos = new WorldPos(0, 64, 0, Space.INSTANCE.getDimensionId());
    private WorldPos spawnPos;
//    private BlockPos startMinecartRidingCoordinate;
    public int experienceLevel;
    public int experienceTotal;
    public float experience;
    protected int xpSeed;
    private ItemStack itemInUse;
    private int itemInUseCount;
    protected float speedInAir = 0.02F;
    private int lastXPSound;
    public EntityHook fishEntity;
    protected int sinceLastAttack;
    
    private boolean otherPlayerUsing;
    private int otherPlayerMPPosRotationIncrements;
    private double otherPlayerMPX;
    private double otherPlayerMPY;
    private double otherPlayerMPZ;
    private double otherPlayerMPYaw;
    private double otherPlayerMPPitch;
    
    private double lastReportedPosX;
    private double lastReportedPosY;
    private double lastReportedPosZ;
    private float lastReportedYaw;
    private float lastReportedPitch;
    private boolean serverSneakState;
    private boolean serverSprintState;
    private int positionUpdateTicks;
    private boolean hasValidHealth;
    protected int sprintToggleTimer;
    public int sprintingTicksLeft;
    public float renderArmYaw;
    public float renderArmPitch;
    public float prevRenderArmYaw;
    public float prevRenderArmPitch;
    private int horseJumpPowerCounter;
    private float horseJumpPower;
//    public float nausea;
//    public float prevNausea;

    public EntityNPC(World worldIn)
    {
        super(worldIn);
        this.species = SpeciesRegistry.CLASSES.get(this.getClass());
        this.extraInventory = new InventoryBasic("Items", false, 8);
//        this.setCharacter("");
        if(this.species != null)
        	this.setSize(this.getSpeciesBaseSize() * this.species.renderer.width / this.species.renderer.height, this.getSpeciesBaseSize()); // /* 0.6F, */ 1.8F);
        if(this.getNavigator() instanceof PathNavigateGround) {
	        ((PathNavigateGround)this.getNavigator()).setBreakDoors(true);
	        ((PathNavigateGround)this.getNavigator()).setAvoidsWater(true);
        }
        this.tasks.addTask(0, new EntityAISwimming(this));
//        this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityNPC.class, 0.6D, true, true));
//        this.tasks.addTask(1, new EntityAIAttackOnCollide(this, EntityLivingBase.class, 0.6D, true, true));
        this.tasks.addTask(1, new EntityAINpcMate(this));
        this.tasks.addTask(2, new EntityAIAvoidEntity(this, EntityLiving.class, new Predicate<EntityLiving>() {
			public boolean test(EntityLiving entity) {
				return entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity);
			}
		}, 8.0F, 1.1D, 1.1D) {
        	{
        		this.setMutexBits(0);
        	}
        	
        	public void startExecuting() {
                EntityNPC.this.setAttackTarget(null);
                EntityNPC.this.fleeing = true;
            }
        	
        	public boolean continueExecuting() {
                return false;
            }

            public void updateTask()
            {
            }
        	
//        	public void resetTask() {
//                super.resetTask();
//                EntityNPC.this.isFleeing = false;
//            }
        });
        this.tasks.addTask(3, new EntityAIAvoidEntity(this, EntityLiving.class, new Predicate<EntityLiving>() {
			public boolean test(EntityLiving entity) {
				return entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity);
			}
		}, 8.0F, 1.1D, 1.1D) {
        	public void startExecuting() {
        		super.startExecuting();
                EntityNPC.this.setAttackTarget(null);
                EntityNPC.this.fleeing = true;
            }
        	
        	public void resetTask() {
                super.resetTask();
                EntityNPC.this.fleeing = false;
            }
        });
//        this.tasks.addTask(2, new EntityAITempt(this, 1.0D, Items.golden_apple, false));
        this.tasks.addTask(4, new EntityAIOpenDoor(this, true));
        this.tasks.addTask(5, new EntityAINagPlayer(this));
        this.tasks.addTask(5, new EntityAILookAtTalkingPlayer(this));
        this.tasks.addTask(6, new EntityAIWatchClosest2(this, null, 3.0F, 1.0F) {
        	private int sneakTime;
        	
        	public void updateTask()
            {
                super.updateTask();
                boolean flag = this.closestEntity.isPlayer() && this.closestEntity.isSneaking();
                if(this.sneakTime > 0) {
                	if(--this.sneakTime == 0) {
                		EntityNPC.this.setSneaking(false);
                	}
                }
                else if(EntityNPC.this.getAttackTarget() == null && EntityNPC.this.rand.chance(flag ? 5 : 200)) {
                	EntityNPC.this.setSneaking(true);
                	this.sneakTime = EntityNPC.this.rand.range(60, flag ? 160 : 120);
                }
                else if(EntityNPC.this.getAttackTarget() != null) {
                	EntityNPC.this.setSneaking(false);
                	this.sneakTime = 0;
                }
            }
        	
        	public void resetTask()
            {
                super.resetTask();
                EntityNPC.this.setSneaking(false);
            }
        });
        this.tasks.addTask(7, new EntityAINpcInteract(this));
        this.tasks.addTask(8, new EntityAIWander(this, 1.0D));
        this.tasks.addTask(8, new EntityAIPlay(this, 1.1D));
        this.tasks.addTask(9, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F));
        this.targets.addTask(1, new EntityAIHurtByTarget(this, false, /* EntityNPC.class, */ EntityLiving.class) {
            protected boolean isSuitableTarget(EntityLiving entity) {
            	if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) {
            		EntityNPC.this.setAttackTarget(null);
                    EntityNPC.this.fleeing = true;
            		return false;
            	}
				return entity != null && entity != EntityNPC.this && (!(entity.isPlayer()) || EntityNPC.this.rand.chance(entity.getAttackedBy() == EntityNPC.this ? 2 : 4))
						&& EntityNPC.this.canCounter(entity) && super.isSuitableTarget(entity);
            }
        });
        this.targets.addTask(2, new EntityAINearestAttackableTarget(this, EntityLiving.class, 10, true, false, new Predicate<EntityLiving>() {
			public boolean test(EntityLiving entity) {
            	if(entity != null && entity != EntityNPC.this && EntityNPC.this.shouldFlee(entity)) {
            		EntityNPC.this.setAttackTarget(null);
                    EntityNPC.this.fleeing = true;
            		return false;
            	}
				return entity != null && entity != EntityNPC.this && !EntityNPC.this.fleeing && EntityNPC.this.canAmbush(entity) && EntityNPC.this.canAttack(entity);
			}
		}));
//        this.setCanPickUpLoot(true);
        
        if (worldIn != null && !worldIn.client)
        {
            this.setCombatTask();
        }
    }
    

    
    private void initPlayer() {
    	this.inventory = new InventoryPlayer(this);
    	this.warpChest = new InventoryWarpChest();
//        this.setHeight(1.8f);
        this.inventoryContainer = new ContainerPlayer(this.inventory, !this.worldObj.client, this);
        this.openContainer = this.inventoryContainer;
        this.setLocationAndAngles(0.5D, 1.0D, 0.5D, 0.0F, 0.0F);
        this.fireResistance = 20;
        this.noPickup = true;
//        this.getEntityAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(1.0D);
        this.getEntityAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.getEntityAttribute(Attributes.MOVEMENT_SPEED).getBaseValue() / 3.0); // 0.10000000149011612D);
    }
    
    public final void setServerPlayer(IPlayer connection) {
    	this.initPlayer();
    	this.connection = connection;
		this.stepHeight = 0.0F;
    }
    
    public final void setClientPlayer(IClientPlayer connection) {
    	this.initPlayer();
		this.slave = true;
    	this.client = connection;
    }
    
    public final void setOtherPlayer() {
    	this.initPlayer();
		this.slave = true;
		this.stepHeight = 0.0F;
		this.noClip = true;
        this.renderDistWeight = 10.0D;
    }
    
    public final boolean isPlayer() {
        return this.connection != null || this.slave;
    }
    

    
    public final boolean canInfight(Alignment align) {
    	return this.alignment.chaotic || (!this.alignment.lawful && 
    			((this.alignment.good && align.evil) || (this.alignment.evil && align.good)));
    }
    
    public final boolean canMurder(Alignment align) {
    	return this.alignment.chaotic && ((this.alignment.good && align.evil) || (this.alignment.evil && align.good));
    }
    
    public boolean canCounter(EntityLiving entity) {
		return !(entity instanceof EntityNPC) || 
			(this.getClass() == entity.getClass() ? this.canInfight(((EntityNPC)entity).alignment) : 
				!this.isPeaceful(((EntityNPC)entity).getClass()));
    }
    
    public boolean canAttack(EntityLiving entity) {
		return entity instanceof EntityNPC && (this.getClass() == entity.getClass() ? this.canMurder(((EntityNPC)entity).alignment) : 
				this.isAggressive(((EntityNPC)entity).getClass()));
    }
    
    public boolean canAmbush(EntityLiving entity) {
    	return true;
    }
    
    public boolean shouldFlee(EntityLiving entity) {
    	return (this.getHealth() <= (this.getMaxHealth() / 4) || !this.canCounter(entity)) && 
    			((entity instanceof EntityNPC && (((EntityNPC)entity).canAttack(this)) || 
    			(entity == this.getAttackedBy() && ((EntityNPC)entity).canCounter(this))));
    }
    
//    public void setCombatTask()
//    {
//    }
    
    public boolean isRangedWeapon(ItemStack stack) {
    	return stack != null && (stack.getItem() == Items.bow || stack.getItem() instanceof ItemGunBase || 
    			stack.getItem() == Items.snowball || stack.getItem() == Items.potion);
    }
    
//    public boolean isSneaking()
//    {
//        return true;
//    }
    
    protected int getAttackSpeed() {
    	return 20;
    }
    
//    public void setScaleForAge()
//    {
//    }
    
//    public float getRenderScale()
//    {
//        return ;
//    }
    
    public boolean isAttacking()
    {
        return this.getFlag(3);
    }

    public void setAttacking(boolean atk)
    {
        this.setFlag(3, atk);
    }
    
//    public boolean isUsingItem()
//    {
//        return ;
//    }

    public void setUsingItem(boolean use)
    {
        this.setFlag(4, use);
    }
    
    public boolean isMating()
    {
        return this.getFlag(5);
    }

    public void setMating(boolean mating)
    {
        this.setFlag(5, mating);
    }
    
    public boolean hasArmsRaised()
    {
        return false;
    }
    
    public boolean hasPowerRods() {
        return false;
    }
    
    public boolean hasDualWings() {
        return false;
    }
    
    public boolean hasSlimArms() {
        return false;
    }
    
    public boolean isCharged()
    {
        return false;
    }
    
//    protected boolean getNpcFlag(int flag)
//    {
//        return (this.dataWatcher.getWatchableObjectByte(20) & 1 << flag) != 0;
//    }
//    
//    protected void setNpcFlag(int flag, boolean set)
//    {
//        byte b0 = this.dataWatcher.getWatchableObjectByte(20);
//
//        if (set)
//        {
//            this.dataWatcher.updateObject(20, Byte.valueOf((byte)(b0 | 1 << flag)));
//        }
//        else
//        {
//            this.dataWatcher.updateObject(20, Byte.valueOf((byte)(b0 & ~(1 << flag))));
//        }
//    }

    protected void applyEntityAttributes()
    {
        super.applyEntityAttributes();
        this.getEntityAttribute(Attributes.FOLLOW_RANGE).setBaseValue(20.0D);
        this.getAttributeMap().registerAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(2.0D);
        this.getEntityAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.3D);
        this.setMaxHealth(this.getBaseHealth(this.rand));
        this.getAttributeMap().registerAttribute(Attributes.MANA_CAPACITY);
        this.getEntityAttribute(Attributes.MANA_CAPACITY).setBaseValue(20.0D);
    }
    
//    protected int getExperiencePoints(EntityNPC player)
//    {
//        return ;
//    }
    
    protected void consumeItemFromStack(EntityNPC player, ItemStack stack)
    {
//        if (!player.creative)
//        {
        --stack.stackSize;

        if (stack.stackSize <= 0)
        {
            player.inventory.setInventorySlotContents(player.inventory.currentItem, (ItemStack)null);
        }
//        }
    }
    
//    protected boolean canDropLoot()
//    {
//        return true;
//    }
    
//    protected float getSoundPitch()
//    {
//        return (this.rand.floatv() - this.rand.floatv()) * 0.2F + 1.0F;
//    }
    
    protected void updateAITasks()
    {
        if (this.getGrowingAge() != 0)
        {
            this.setMating(false);
        }

        super.updateAITasks();
    }
    
    private void onNpcUpdate()
    {
        super.onLivingUpdate();

		if(!this.worldObj.client && /* this.canPickUpLoot() && */ !this.noPickup && Config.mobGrief) {
			for(EntityItem entityitem : this.worldObj.getEntitiesWithinAABB(EntityItem.class, this.getEntityBoundingBox().expand(1.0D, 0.0D, 1.0D))) {
				if(!entityitem.dead && entityitem.getEntityItem() != null && !entityitem.cannotPickup()) {
					this.updateEquipmentIfNeeded(entityitem);
				}
			}
		}

        if (this.getGrowingAge() != 0)
        {
            this.setMating(false);
        }

        if(this.worldObj.client) {
	        if (this.isMating())
	        {
	            ++this.inLove;
	
	            if (this.inLove == 10)
	            {
	            	this.inLove = 0;
	                double d0 = this.rand.gaussian() * 0.02D;
	                double d1 = this.rand.gaussian() * 0.02D;
	                double d2 = this.rand.gaussian() * 0.02D;
	                this.worldObj.spawnParticle(ParticleType.HEART, this.posX + (double)(this.rand.floatv() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.floatv() * this.height), this.posZ + (double)(this.rand.floatv() * this.width * 2.0F) - (double)this.width, d0, d1, d2);
	            }
	        }
	        else {
	        	this.inLove = 0;
	        }
        }
    }
    
    public boolean interact(EntityNPC player)
    {
        ItemStack itemstack = player.inventory.getCurrentItem();
        boolean flag = itemstack != null && !(itemstack.getItem() instanceof ItemTool || itemstack.getItem() instanceof ItemSword || 
        		itemstack.getItem() instanceof ItemHoe || itemstack.getItem() instanceof ItemShears);

        if (itemstack != null && !this.isPlayer() && this.isBreedingItem(itemstack) && this.getGrowingAge() == 0 && !this.isMating())
        {
            this.consumeItemFromStack(player, itemstack);
        	if (!this.worldObj.client)
            {
	            this.setIsWillingToMate(true);
	            this.setMating(true);
	            this.worldObj.setEntityState(this, (byte)12);
            }
            return true;
        }
        else if (itemstack != null && !this.isPlayer() && this.isBreedingItem(itemstack) && this.getGrowingAge() < 0)
        {
            this.consumeItemFromStack(player, itemstack);
        	if (!this.worldObj.client)
            {
	            this.grow(this.rand.range(200, 250));
            }
//        	else if (this.particleTimer == 0) {
//                this.particleTimer = 40;
//        	}
            return true;
        }
        else if (!flag && !this.isPlayer() && this.isEntityAlive() && !this.isTalking())
        {
            if (!this.worldObj.client && this.canTrade() && this.getAttackTarget() == null)
            {
                this.setTalking(player);
				player.connection.displayTradeGui(this);
            }

//            player.triggerAchievement(StatRegistry.timesTalkedToNpcStat);
            return true;
        }
        else
        {
            return super.interact(player);
        }
    }
    
//    public boolean attackEntityFrom(DamageSource source, int amount)
//    {
//    }

    public boolean attackEntityAsMob(Entity entityIn)
    {
    	if(!this.worldObj.client && !Config.damageMobs)
    		return false;
        int f = (int)this.getEntityAttribute(Attributes.ATTACK_DAMAGE).getAttributeValue();
        int i = 0;

        if (entityIn instanceof EntityLiving)
        {
            f += EnchantmentHelper.getDamageModifier(this.getHeldItem());
            i += EnchantmentHelper.getKnockbackModifier(this);
        }

        boolean flag = entityIn.attackEntityFrom(DamageSource.causeMobDamage(this), f);

        if (flag)
        {
            if (i > 0)
            {
                entityIn.addKnockback((double)(-ExtMath.sin(this.rotYaw * (float)Math.PI / 180.0F) * (float)i * 0.5F), 0.1D, (double)(ExtMath.cos(this.rotYaw * (float)Math.PI / 180.0F) * (float)i * 0.5F));
                this.motionX *= 0.6D;
                this.motionZ *= 0.6D;
            }

            int j = EnchantmentHelper.getFireAspectModifier(this);

            if (j > 0)
            {
                entityIn.setFire(j * 4);
            }

            this.applyEnchantments(this, entityIn);
        }

        return flag;
    }
    
    public void attackEntityWithRangedAttack(EntityLiving target, float range)
    {
    	ItemStack stack = this.getHeldItem();
    	if(stack == null)
    		return;
    	if(stack.getItem() == Items.bow) {
	        EntityArrow entityarrow = new EntityArrow(this.worldObj, this, target, 1.6F, 2.0f);
	        int i = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, this.getHeldItem());
	        int j = EnchantmentHelper.getEnchantmentLevel(Enchantment.punch.effectId, this.getHeldItem());
	        entityarrow.setDamage((double)(range * 2.0F) + this.rand.gaussian() * 0.25D + (double)(/* (float)this.worldObj.getDifficulty().getId() */ 3.0f * 0.11F));
	
	        if (i > 0)
	        {
	            entityarrow.setDamage(entityarrow.getDamage() + (double)i * 0.5D + 0.5D);
	        }
	
	        if (j > 0)
	        {
	            entityarrow.setKnockbackStrength(j);
	        }
	
	        if (EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, this.getHeldItem()) > 0)
	        {
	            entityarrow.setFire(100);
	        }
	
	        this.playSound(SoundEvent.THROW, 1.0F);
	        this.worldObj.spawnEntityInWorld(entityarrow);
    	}
    	else if(stack.getItem() instanceof ItemGunBase) {
    		EntityBullet bullet = new EntityBullet(this.worldObj, this, target, ((ItemGunBase)stack.getItem()).getVelocity(), 0.75f);
	        int i = EnchantmentHelper.getEnchantmentLevel(Enchantment.power.effectId, this.getHeldItem());
//	        int j = EnchantmentHelper.getEnchantmentLevel(Enchantment.punch.effectId, this.getHeldItem());
	        bullet.setDamage(((ItemGunBase)stack.getItem()).getAmmo().getDamage(stack));
	
	        if (i > 0)
	        {
	            bullet.setDamage(bullet.getDamage() + i);
	        }
	
//	        if (j > 0)
//	        {
//	            entityarrow.setKnockbackStrength(j);
//	        }
	
//	        if (EnchantmentHelper.getEnchantmentLevel(Enchantment.flame.effectId, this.getHeldItem()) > 0)
//	        {
//	            entityarrow.setFire(100);
//	        }
	
	        this.playSound(SoundEvent.EXPLODE_ALT, 1.0f);
	        this.worldObj.spawnEntityInWorld(bullet);
    	}
    	else if(stack.getItem() == Items.snowball) {
    		EntitySnowball entitysnowball = new EntitySnowball(this.worldObj, this);
            double d0 = target.posY + (double)target.getEyeHeight() - 1.100000023841858D;
            double d1 = target.posX - this.posX;
            double d2 = d0 - entitysnowball.posY;
            double d3 = target.posZ - this.posZ;
            float f = ExtMath.sqrtd(d1 * d1 + d3 * d3) * 0.2F;
            entitysnowball.setThrowableHeading(d1, d2 + (double)f, d3, 1.6F, 12.0F);
            this.playSound(SoundEvent.THROW, 1.0F);
            this.worldObj.spawnEntityInWorld(entitysnowball);
    	}
    	else if(stack.getItem() == Items.potion) {
            EntityPotion entitypotion = new EntityPotion(this.worldObj, this, 32732);
            double d0 = target.posY + (double)target.getEyeHeight() - 1.100000023841858D;
            entitypotion.rotPitch -= -20.0F;
            double d1 = target.posX + target.motionX - this.posX;
            double d2 = d0 - this.posY;
            double d3 = target.posZ + target.motionZ - this.posZ;
            float f = ExtMath.sqrtd(d1 * d1 + d3 * d3);

            if (f >= 8.0F && !target.hasEffect(Potion.SLOWNESS))
            {
                entitypotion.setPotionDamage(32698);
            }
            else if (target.getHealth() >= 8 && !target.hasEffect(Potion.POISON))
            {
                entitypotion.setPotionDamage(32660);
            }
            else if (f <= 3.0F && !target.hasEffect(Potion.WEAKNESS) && this.rand.floatv() < 0.25F)
            {
                entitypotion.setPotionDamage(32696);
            }

            entitypotion.setThrowableHeading(d1, d2 + (double)(f * 0.2F), d3, 1.5F, 0.5F);
            this.worldObj.spawnEntityInWorld(entitypotion);
    	}
    }

//    protected void entityInit()
//    {
//    }
    
//    public void writeEntityToNBT(NBTTagCompound tagCompound)
//    {
//    }
    
//    public void readEntityFromNBT(NBTTagCompound tagCompund)
//    {
//    }
    
//    protected boolean canDespawn()
//    {
//        return false;
//    }
    
//    protected String getHurtSound()
//    {
//        return "mob.npc.hit";
//    }
//    
//    protected String getDeathSound()
//    {
//        return "mob.npc.death";
//    }

    public void setChar(String character)
    {
        this.dataWatcher.updateObject(16, character);
    }

    public String getChar()
    {
        return this.dataWatcher.getWatchableObjectString(16);
    }

    public void setCape(String cape)
    {
        this.dataWatcher.updateObject(17, cape);
    }

    public String getCape()
    {
        return this.dataWatcher.getWatchableObjectString(17);
    }

    public void setNpcClass(Enum type)
    {
        this.dataWatcher.updateObject(22, (byte)(type == null ? -1 : type.ordinal()));
    }

    public Enum getNpcClass()
    {
    	byte n = this.dataWatcher.getWatchableObjectByte(22);
        return n < 0 || this.species == null || this.species.classEnum == null ? null : 
        	this.species.classEnum.getEnumConstants()[n % this.species.classEnum.getEnumConstants().length];
    }

    public void setAlignment(Alignment align)
    {
    	this.alignment = align;
        this.dataWatcher.updateObject(18, (byte)align.ordinal());
    }

    public Alignment getAlignment()
    {
        return Alignment.values()[this.dataWatcher.getWatchableObjectByte(18) % Alignment.values().length];
    }

    public void setHeight(float height)
    {
        this.dataWatcher.updateObject(29, ExtMath.clampf(height, 0.2f, 10.0f));
    }

    public float getHeight()
    {
        return this.dataWatcher.getWatchableObjectFloat(29);
    }

    public SpeciesInfo getSpecies() {
    	return this.species;
    }
    
    public void setAttackedBy(EntityLiving livingBase)
    {
        if(livingBase != null && /* livingBase.isPlayer() && */ this.isEntityAlive() && /* !this.isPeaceful() && */ this.getAttackedBy() != livingBase && 
        		Config.mobAttacks) {
            this.worldObj.setEntityState(this, (byte)13);
        }
        super.setAttackedBy(livingBase);
    }
    
//    public void onDeath(DamageSource cause)
//    {
//
//        super.onDeath(cause);
//    }
    
//    protected void dropEquipment()
//    {
//    }

    public void setTalking(EntityNPC player)
    {
        this.talkingPlayer = player;
    }

    public EntityNPC getTalking()
    {
        return this.talkingPlayer;
    }

    public boolean isTalking()
    {
        return this.talkingPlayer != null;
    }
    
    public boolean canMate()
    {
        return false;
    }
    
    public boolean getIsWillingToMate(boolean update)
    {
        if (!this.isWilling && update && this.canMate())
        {
        	this.isWilling = true;
        }

        return this.isWilling;
    }

    public void setIsWillingToMate(boolean willing)
    {
        this.isWilling = willing;
        if(!this.isWilling) {
        	this.setMating(false);
        }
    }
    
    public String getPrefix() {
        Enum cls = this.species.prefix ? this.getNpcClass() : null;
    	return cls == null ? null : cls.toString();
    }
    
//    public String getName()
//    {
//    }
    
//    public String formatStats() {
//    	return super.formatStats();
//    }

//    public float getEyeHeight()
//    {
////        float f = 1.62F;
////
////        if (this.isChild())
////        {
////            f = (float)((double)f - 0.81D);
////        }
//
//    }

//    public void handleStatusUpdate(byte id)
//    {
//    }
    
//    public Object onInitialSpawn(Object livingdata)
//    {
//    }

	public boolean isPropogatingSpawnData(boolean newGroup) {
		return true;
	}
	
	protected ItemStack pickItem() {
		return null;
	}

	protected ItemStack pickArmor(int slot) {
		return null;
	}

	protected ItemStack pickLoot(int slot) {
		return null;
	}
	
	protected int pickItemAmount() {
		return this.rand.zrange(4);
	}
	
//    public EntityNPC createChild(EntityLiving ageable)
//    {
//    }
    
//    public void onStruckByLightning(EntityLightning lightningBolt)
//    {
//        if (!this.worldObj.client && !this.isDead)
//        {
//        	
//        }
//        
//        super.onStruckByLightning(lightningBolt);
//    }

    public InventoryBasic getExtendedInventory()
    {
        return this.extraInventory;
    }
    
//    protected void updateEquipmentIfNeeded(EntityItem itemEntity)
//    {
//    	super.updateEquipmentIfNeeded(itemEntity);
//    	if(!itemEntity.dead) {
//	        ItemStack stack = itemEntity.getEntityItem();
//	        Item item = stack.getItem();
//	
//	        if (this.canPickUpExtraItem(item))
//	        {
//	            ItemStack remain = this.extraInventory.addStack(stack);
//	
//	            if (remain == null)
//	            {
//	                itemEntity.setDead();
//	            }
//	            else
//	            {
//	                stack.stackSize = remain.stackSize;
//	            }
//	        }
//    	}
//    }

    private boolean canPickUpExtraItem(Item itemIn)
    {
        return itemIn == Items.golden_apple || itemIn == Items.sugar;
    }

//    public LayerExtra getExtrasLayer()
//    {
//        return ;
//    }

//    public String getLocationSkin()
//    {
//        return ;
//    }

//    protected boolean hasSlimSkin()
//    {
//        return this.getChar().startsWith("~");
//    }
    
//    public boolean canRenderExtras()
//    {
//        return true;
//    }

//    public boolean isWearing(ModelPart part)
//    {
//        return ;
//    }
    
    public int getLeashColor() {
    	return 0x202020;
    }
    
    public int getManaPoints() {
    	return this.dataWatcher.getWatchableObjectInt(21);
    }
    
    public void setManaPoints(int pts) {
    	this.dataWatcher.updateObject(21, pts);
    }

//    public final boolean isAggressive() {
//    	return this.alignment.evil;
//    }
//    
//    public final boolean isPeaceful() {
//    	return this.alignment.good;
//    }
    
    public boolean isAggressive(Class<? extends EntityNPC> clazz) {
    	return false;
    }
    
    public boolean isPeaceful(Class<? extends EntityNPC> clazz) {
    	return false;
    }
    
    public boolean canUseMagic() {
    	return false;
    }
    
//    public abstract int getBaseHealth(Random rand);
    
//    public final int getBaseEnergy(Random rand) {
//    	return 0;
//    }
    
    public final float getHeightDeviation(Random rand) {
    	return this.getHeightDeviationMin() == this.getHeightDeviationMax() ? this.getHeightDeviationMin() : this.rand.frange(this.getHeightDeviationMin(), this.getHeightDeviationMax());
    }

    public float getHeightDeviationMin() {
    	return 0.0f;
    }

    public float getHeightDeviationMax() {
    	return 0.0f;
    }

    public abstract float getSpeciesBaseSize();

    public float getEntityBaseSize() {
    	return this.getSpeciesBaseSize();
    }

    public boolean isVisibleTo(EntityNPC player)
    {
        return this.connection == null || !this.connection.isInEditor();
    }
    
//    public abstract Alignment getNaturalAlign();
    
//    public float getBaseSize(Random rand) {
//    	return ;
//    }
    
    public boolean isBreedingItem(ItemStack stack)
    {
        return false;
    }
    
    public boolean canTrade()
    {
        return false;
    }
    
    public NameRegistry getNameType()
    {
        return NameRegistry.FANTASY;
    }
    
    public String pickRandomName()
    {
        return this.getNameType().generate(this.rand, this.rand.chance(40) ? (this.rand.chance(15) ? 5 : 4) : (this.rand.chance() ? 3 : 2));
    }
    
//	public int getColor() {
//		return ;
//	}

	public void setPlaying(boolean playing) {
		this.playing = playing;
	}

	public boolean isPlaying() {
		return this.playing;
	}

	public boolean isFleeing() {
		return this.fleeing;
	}

//	public boolean canPlay() {
//		return ;
//	}
	
//	public boolean isChild() {
//		return false;
//	}
    
//    protected int decreaseAirSupply(int air) {
//        return air;
//    }

    public int getMaxMana() {
        return (int)this.getEntityAttribute(Attributes.MANA_CAPACITY).getAttributeValue();
    }

	public MerchantRecipeList getTrades(EntityNPC player) {
		if(this.trades == null) {
			this.trades = new MerchantRecipeList();
			int n = this.rand.range(5, 25);
			for(int z = 0; z < n; z++) {
				this.rand.pick(TradeRegistry.TRADES).modifyMerchantRecipeList(this.trades, this.rand);
			}
		}
		return this.trades;
	}
	
//    public boolean isNotColliding() {
//        return this.canSpawnInLiquid() ? 
//        		(this.worldObj.checkNoEntityCollision(this.getEntityBoundingBox(), this) && 
//        		this.worldObj.getCollidingBoundingBoxes(this, this.getEntityBoundingBox()).isEmpty() 
//        		/* && !this.worldObj.isAnyLiquid(this.getEntityBoundingBox()) */) : super.isNotColliding();
//    }
    
    protected int applyPotionDamageCalculations(DamageSource source, int damage) {
        damage = super.applyPotionDamageCalculations(source, damage);
        if(this.canUseMagic() && source.isMagicDamage())
            damage = source.getEntity() == this ? 0 : (int)((double)damage * 0.15D);
        return damage;
    }
    

	protected boolean teleportRandomly() {
		double x = this.posX + (this.rand.doublev() - 0.5D) * 64.0D;
		double y = this.posY + (double)(this.rand.excl(-32, 32));
		double z = this.posZ + (this.rand.doublev() - 0.5D) * 64.0D;
		return this.teleportTo(x, y, z);
	}

	protected boolean teleportToEntity(Entity entity) {
		Vec3 vec3 = new Vec3(this.posX - entity.posX,
				this.getEntityBoundingBox().minY + (double)(this.height / 2.0F) - entity.posY + (double)entity.getEyeHeight(),
				this.posZ - entity.posZ);
		vec3 = vec3.normalize();
		double dist = 16.0D;
		double x = this.posX + (this.rand.doublev() - 0.5D) * 8.0D - vec3.xCoord * dist;
		double y = this.posY + (double)(this.rand.excl(-8, 8)) - vec3.yCoord * dist;
		double z = this.posZ + (this.rand.doublev() - 0.5D) * 8.0D - vec3.zCoord * dist;
		return this.teleportTo(x, y, z);
	}

	protected boolean teleportTo(double x, double y, double z) {
		double ox = this.posX;
		double oy = this.posY;
		double oz = this.posZ;
		this.posX = x;
		this.posY = y;
		this.posZ = z;
		boolean done = false;
		BlockPos pos = new BlockPos(this.posX, this.posY, this.posZ);

		if(this.worldObj.isBlockLoaded(pos)) {
			boolean ground = false;

			while(!ground && pos.getY() > 0) {
				BlockPos down = pos.down();
				Block block = this.worldObj.getState(down).getBlock();

				if(block.getMaterial().blocksMovement()) {
					ground = true;
				}
				else {
					--this.posY;
					pos = down;
				}
			}

			if(ground) {
				super.setPositionAndUpdate(this.posX, this.posY, this.posZ);

				if(this.worldObj.getCollidingBoundingBoxes(this, this.getEntityBoundingBox()).isEmpty()
						&& !this.worldObj.isAnyLiquid(this.getEntityBoundingBox())) {
					done = true;
				}
			}
		}

		if(!done) {
			this.setPosition(ox, oy, oz);
			return false;
		}
		else {
        	this.worldObj.playAuxSFX(1013, new BlockPos(ox, oy, oz), 0);
        	((AWorldServer)this.worldObj).spawnParticle(ParticleType.PORTAL, 
        			ox + (this.rand.doublev() - 0.5D) * (double)this.width * 2.0D, 
        			oy + this.rand.doublev() * (double)this.height, 
        			oz + (this.rand.doublev() - 0.5D) * (double)this.width * 2.0D, 8, 
        			(this.rand.floatv() - 0.5F) * 0.2F, (this.rand.floatv() - 0.5F) * 0.2F, (this.rand.floatv() - 0.5F) * 0.2F, 
        			0.15D);
        	this.worldObj.playAuxSFX(1005, this.getPosition(), 0);
        	((AWorldServer)this.worldObj).spawnParticle(ParticleType.PORTAL, 
        			this.posX + (this.rand.doublev() - 0.5D) * (double)this.width * 2.0D, 
        			this.posY + this.rand.doublev() * (double)this.height, 
        			this.posZ + (this.rand.doublev() - 0.5D) * (double)this.width * 2.0D, 8, 
        			(this.rand.floatv() - 0.5F) * 0.2F, (this.rand.floatv() - 0.5F) * 0.2F, (this.rand.floatv() - 0.5F) * 0.2F, 
        			0.15D);
			return true;
		}
	}
	
	


//	public boolean setSlot(int slot, ItemStack stack) {
//		int i;
//
//		if(slot == 99) {
//			i = 0;
//		}
//		else {
//			i = slot - 100 + 1;
//
//			if(i < 0 || i >= this.equipment.length) {
////				return false;
//				i = slot - 300;
//
//	            if (i >= 0 && i < this.extraInventory.getSizeInventory())
//	            {
//	                this.extraInventory.setInventorySlotContents(i, stack);
//	                return true;
//	            }
//	            else
//	            {
//	                return false;
//	            }
//			}
//		}
//
//		if(stack != null && ItemArmor.getArmorPosition(stack) != i && (i != 4 || !(stack.getItem() instanceof ItemBlock))) {
//			return false;
//		}
//		else {
//			this.setItem(i, stack);
//			return true;
//		}
//	}

//    public boolean setSlot(int slot, ItemStack stack)
//    {
//        if (super.setSlot(slot, stack))
//        {
//            return true;
//        }
//        else
//        {
//            int i = slot - 300;
//
//            if (i >= 0 && i < this.extraInventory.getSizeInventory())
//            {
//                this.extraInventory.setInventorySlotContents(i, stack);
//                return true;
//            }
//            else
//            {
//                return false;
//            }
//        }
//    }

	protected void updateEquipmentIfNeeded(EntityItem itemEntity) {
		ItemStack stack = itemEntity.getEntityItem();
		if(stack.getItem().getRadiation(stack) > 0.0f)
        	return;
		int slot = ItemArmor.getArmorPosition(stack);

		if(slot > -1) {
			boolean flag = true;
			ItemStack old = this.getItem(slot);

			if(old != null) {
				if(slot == 0) {
					if(stack.getItem() instanceof ItemSword && !(old.getItem() instanceof ItemSword)) {
						flag = true;
					}
					else if(stack.getItem() instanceof ItemSword && old.getItem() instanceof ItemSword) {
						ItemSword itemsword = (ItemSword)stack.getItem();
						ItemSword itemsword1 = (ItemSword)old.getItem();

						if(itemsword.getDamageVsEntity() != itemsword1.getDamageVsEntity()) {
							flag = itemsword.getDamageVsEntity() > itemsword1.getDamageVsEntity();
						}
						else {
							flag = stack.getMetadata() > old.getMetadata() || stack.hasTagCompound() && !old.hasTagCompound();
						}
					}
					else if(stack.getItem() instanceof ItemBow && old.getItem() instanceof ItemBow) {
						flag = stack.hasTagCompound() && !old.hasTagCompound();
					}
					else if(stack.getItem() instanceof ItemGunBase && !(old.getItem() instanceof ItemBow)) {
						flag = true;
					}
					else if(stack.getItem() instanceof ItemBow && !(old.getItem() instanceof ItemBow) && !(old.getItem() instanceof ItemSword)) {
						flag = true;
					}
					else {
						flag = false;
					}
				}
				else if(stack.getItem() instanceof ItemArmor && !(old.getItem() instanceof ItemArmor)) {
					flag = true;
				}
				else if(stack.getItem() instanceof ItemArmor && old.getItem() instanceof ItemArmor) {
					ItemArmor itemarmor = (ItemArmor)stack.getItem();
					ItemArmor itemarmor1 = (ItemArmor)old.getItem();

					if(itemarmor.damageReduceAmount != itemarmor1.damageReduceAmount) {
						flag = itemarmor.damageReduceAmount > itemarmor1.damageReduceAmount;
					}
					else {
						flag = stack.getMetadata() > old.getMetadata() || stack.hasTagCompound() && !old.hasTagCompound();
					}
				}
				else {
					flag = false;
				}
			}

			if(flag) { // && this.canPickUpItem(stack)) {
				if(old != null) { // && this.rand.floatv() - 0.1F < this.dropChances[slot]) {
					this.entityDropItem(old, 0.0F);
				}

//				if(stack.getItem() == Items.diamond && itemEntity.getThrower() != null) {
//					EntityNPC entityplayer = this.worldObj.getPlayer(itemEntity.getThrower());
//
//					if(entityplayer != null) {
//						entityplayer.triggerAchievement(AchievementList.diamondsToYou);
//					}
//				}

				this.setItem(slot, stack);
//				this.dropChances[slot] = 2.0F;
//				this.noDespawn = true;
				this.onItemPickup(itemEntity, 1);
				itemEntity.setDead();
			}
		}
    	if(!itemEntity.dead) {
	        stack = itemEntity.getEntityItem();
	        Item item = stack.getItem();
	
	        if (this.canPickUpExtraItem(item))
	        {
	            ItemStack remain = this.extraInventory.addStack(stack);
	
	            if (remain == null)
	            {
	                itemEntity.setDead();
	            }
	            else
	            {
	                stack.stackSize = remain.stackSize;
	            }
	        }
    	}
	}

//	protected void dropEquipment(boolean wasRecentlyHit, int lootingModifier) {
//		for(int i = 0; i < this.getInventory().length; ++i) {
//			ItemStack itemstack = this.getItem(i);
//			boolean flag = this.dropChances[i] > 1.0F;
//
//			if(itemstack != null && (wasRecentlyHit || flag) && this.rand.floatv() - (float)lootingModifier * 0.01F < this.dropChances[i]) {
//				if(!flag && itemstack.isItemStackDamageable()) {
//					int j = Math.max(itemstack.getMaxDamage() - 25, 1);
//					int k = itemstack.getMaxDamage() - this.rand.zrange(this.rand.roll(j));
//
//					if(k > j) {
//						k = j;
//					}
//
//					if(k < 1) {
//						k = 1;
//					}
//
//					itemstack.setItemDamage(k);
//				}
//
//				this.entityDropItem(itemstack, 0.0F);
//			}
//		}
//	}

//	protected boolean canPickUpItem(ItemStack stack) {
//		return true;
//	}
//
//	public boolean canPickUpLoot() {
//		return this.canPickUpLoot;
//	}
//
//	public void setCanPickUpLoot(boolean canPickup) {
//		this.canPickUpLoot = canPickup;
//	}
	
//	protected void dropFewItems(boolean wasRecentlyHit, int lootingModifier) {
//	}

	

//	public static Item getArmorItemForSlot(int armorSlot, int itemTier) {
//		switch(armorSlot)
//		{
//		case 4:
//			if(itemTier == 0) {
//				return Items.leather_helmet;
//			}
//			else if(itemTier == 1) {
//				return Items.gold_helmet;
//			}
//			else if(itemTier == 2) {
//				return Items.chain_helmet;
//			}
//			else if(itemTier == 3) {
//				return Items.iron_helmet;
//			}
//			else if(itemTier == 4) {
//				return Items.diamond_helmet;
//			}
//
//		case 3:
//			if(itemTier == 0) {
//				return Items.leather_chestplate;
//			}
//			else if(itemTier == 1) {
//				return Items.gold_chestplate;
//			}
//			else if(itemTier == 2) {
//				return Items.chain_chestplate;
//			}
//			else if(itemTier == 3) {
//				return Items.iron_chestplate;
//			}
//			else if(itemTier == 4) {
//				return Items.diamond_chestplate;
//			}
//
//		case 2:
//			if(itemTier == 0) {
//				return Items.leather_leggings;
//			}
//			else if(itemTier == 1) {
//				return Items.gold_leggings;
//			}
//			else if(itemTier == 2) {
//				return Items.chain_leggings;
//			}
//			else if(itemTier == 3) {
//				return Items.iron_leggings;
//			}
//			else if(itemTier == 4) {
//				return Items.diamond_leggings;
//			}
//
//		case 1:
//			if(itemTier == 0) {
//				return Items.leather_boots;
//			}
//			else if(itemTier == 1) {
//				return Items.gold_boots;
//			}
//			else if(itemTier == 2) {
//				return Items.chain_boots;
//			}
//			else if(itemTier == 3) {
//				return Items.iron_boots;
//			}
//			else if(itemTier == 4) {
//				return Items.diamond_boots;
//			}
//
//		default:
//			return null;
//		}
//	}

//	public ItemStack getHeldItem() {
//		return ;
//	}

//	public ItemStack getItem(int slot) {
//		return ;
//	}

//	public ItemStack getArmor(int slot) {
//		return ;
//	}

//	public void setItem(int slot, ItemStack stack) {
//		this.equipment[slot] = stack;
//	}
    
//    public void setItem(int slot, ItemStack stack)
//    {
////        super.setItem(slot, stack);
//    }
    
//    public void setItemNoUpdate(int slot, ItemStack stack)
//    {
//    }

//	public ItemStack[] getInventory() {
//		return ;
//	}
    
//    public int getTrackingRange() {
//    	return 80;
//    }
    
//    public int getUpdateFrequency() {
//    	return 3;
//    }
    
//    public boolean isSendingVeloUpdates() {
//    	return true;
//    }

//	protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty) {
//		if(this.rand.floatv() < 0.15F * difficulty.getDifficulty()) {
//			int i = this.rand.zrange(2);
////			float f = this.worldObj.getDifficulty() == Difficulty.HARD ? 0.1F : 0.25F;
//			float f = 0.1F;
//
//			if(this.rand.floatv() < 0.095F) {
//				++i;
//			}
//
//			if(this.rand.floatv() < 0.095F) {
//				++i;
//			}
//
//			if(this.rand.floatv() < 0.095F) {
//				++i;
//			}
//
//			for(int j = 3; j >= 0; --j) {
//				ItemStack itemstack = this.getArmor(j);
//
//				if(j < 3 && this.rand.floatv() < f) {
//					break;
//				}
//
//				if(itemstack == null) {
//					Item item = getArmorItemForSlot(j + 1, i);
//
//					if(item != null) {
//						this.setItem(j + 1, new ItemStack(item));
//					}
//				}
//			}
//		}
//	}

//	protected void setEnchantmentBasedOnDifficulty(DifficultyInstance difficulty) {
//		float f = difficulty.getDifficulty();
//
//		if(this.getHeldItem() != null && this.rand.floatv() < 0.25F * f) {
//			EnchantmentHelper.addRandomEnchantment(this.rand, this.getHeldItem(), (int)(5.0F + f * (float)this.rand.zrange(18)));
//		}
//
//		for(int i = 0; i < 4; ++i) {
//			ItemStack itemstack = this.getArmor(i);
//
//			if(itemstack != null && this.rand.floatv() < 0.5F * f) {
//				EnchantmentHelper.addRandomEnchantment(this.rand, itemstack, (int)(5.0F + f * (float)this.rand.zrange(18)));
//			}
//		}
//	}
    
    public boolean useMana(int pts) {
    	int mana = this.getManaPoints();
    	if(mana >= pts)
    		this.setManaPoints(mana - pts);
    	return mana >= pts;
    }
    
    private void updateNpc()
    {
    	if(!this.worldObj.client) {
	        for (int j = 0; j < 5; ++j)
	        {
	            ItemStack itemstack = this.prevEquipment[j];
	            ItemStack itemstack1 = this.getItem(j);
	
	            if (!ItemStack.areItemStacksEqual(itemstack1, itemstack))
	            {
	                ((AWorldServer)this.worldObj).sendToAllTrackingEntity(this, new SPacketEntityEquipment(this.getId(), j, itemstack1));
	
	                if (itemstack != null)
	                {
	                    this.getAttributeMap().removeAttributeModifiers(itemstack.getAttributeModifiers(1));
	                }
	
	                if (itemstack1 != null)
	                {
	                    this.getAttributeMap().applyAttributeModifiers(itemstack1.getAttributeModifiers(1));
	                }
	
	                this.prevEquipment[j] = itemstack1 == null ? null : itemstack1.copy();
	            }
	        }
        }
        super.onUpdate();
        if(!this.worldObj.client && Config.regeneration && this.shouldHeal()) {
            ++this.healTimer;

            if(this.healTimer >= 80) {
                this.heal(1);
                this.healTimer = 0;
            }
        }
    }

//	protected void sendDeathMessage() {
//		this.sendDeathMessage(false, true);
//	}

//	protected boolean canRegenerateHealth() {
//		return false;
//	}

	protected boolean shouldHeal() {
        return this.canRegenerateHealth() && Config.healChance > 0 && this.getHealth() > 0 && this.getHealth() < this.getMaxHealth() 
        		&& this.rand.chance(Config.healChance);
    }
    
    public byte[] getSkin() {
    	return this.skin;
    }
    
    public void setSkin(byte[] skin) {
    	this.skin = skin;
    }
    
    
    
    

    
    
    // START SP
    
    public boolean attackEntityFrom(DamageSource source, int amount)
    {
    	if(this.slave)
	        return this.client == null;
//        if(this.isEntityInvulnerable(source))
//            return false;
    	if(this.connection != null) {
	        if(this.getHealth() <= 0)
	            return false;
//            Entity entity = source.getEntity();
//            if(entity instanceof EntityArrow && ((EntityArrow)entity).shootingEntity != null)
//                entity = ((EntityArrow)entity).shootingEntity;
//            return super.attackEntityFrom(source, amount);
    	}
    	else {
	        this.setIsWillingToMate(false);
	        this.setMating(false);
    	}
        return super.attackEntityFrom(source, amount);
    }

    /**
     * Heal living entity (param: amount of half-hearts)
     */
    public void heal(int healAmount)
    {
    	if(this.client == null)
    		super.heal(healAmount);
    }
    
    public void healMana(int amount)
    {
    	if(this.client == null)
    		super.healMana(amount);
    }

    /**
     * Called when a player mounts an entity. e.g. mounts a pig, mounts a boat.
     */
    public void mountEntity(Entity entityIn)
    {
		Entity entity = this.vehicle;
		super.mountEntity(entityIn);
		if(this.connection != null && entityIn != entity)
			this.connection.mountEntity(entityIn);
//        super.mountEntity(entityIn);

        if (this.client != null && entityIn instanceof EntityCart)
        {
            this.client.playSound(new MovingSoundMinecartRiding(this, (EntityCart)entityIn));
        }
    }

    /**
     * Called to update the entity's position/logic.
     */
    public void onUpdate()
    {
    	if(this.client != null) {
	        if (this.worldObj.isBlockLoaded(new BlockPos(this.posX, 0.0D, this.posZ)))
	        {
//	            super.onUpdate();
	            this.updatePlayer();
	
	            if (this.isRiding())
	            {
	                this.client.addToSendQueue(new CPacketPlayer.C05PacketPlayerLook(this.rotYaw, this.rotPitch, this.onGround));
	                this.client.addToSendQueue(new CPacketInput(this.moveStrafe, this.moveForward, this.client.isJumping(), this.client.isSneaking()));
	            }
	            else
	            {
	                this.onUpdateWalkingPlayer();
	            }
	        }
	        return;
    	}

		if(this.connection != null) {
			this.connection.updateEntity();
			return;
		}
		
		if(this.slave) {
	//        this.renderOffsetY = 0.0F;
//	        super.onUpdate();
	        this.updatePlayer();
	        this.prevLswingAmount = this.lswingAmount;
	        double d0 = this.posX - this.prevX;
	        double d1 = this.posZ - this.prevZ;
	        float f = ExtMath.sqrtd(d0 * d0 + d1 * d1) * 4.0F;
	
	        if (f > 1.0F)
	        {
	            f = 1.0F;
	        }
	
	        this.lswingAmount += (f - this.lswingAmount) * 0.4F;
	        this.limbSwing += this.lswingAmount;
	
	        if (!this.otherPlayerUsing && this.isUsingItem() && this.inventory.mainInventory[this.inventory.currentItem] != null)
	        {
	            ItemStack itemstack = this.inventory.mainInventory[this.inventory.currentItem];
	            this.setItemInUse(this.inventory.mainInventory[this.inventory.currentItem], itemstack.getItem().getMaxItemUseDuration(itemstack));
	            this.otherPlayerUsing = true;
	        }
	        else if (this.otherPlayerUsing && !this.isUsingItem())
	        {
	            this.clearItemInUse();
	            this.otherPlayerUsing = false;
	        }
			return;
    	}

        this.updateNpc();
//        this.updatePlayer();
    }
    
    private void updatePlayer() {
    	this.noClip = this.noclip;

        if (this.noclip)
        {
            this.onGround = false;
        }

        if (this.itemInUse != null)
        {
            ItemStack itemstack = this.inventory.getCurrentItem();

            if (itemstack == this.itemInUse)
            {
                if (this.itemInUseCount <= 25 && this.itemInUseCount % 4 == 0)
                {
                    this.updateItemUse(itemstack, 5);
                }

                if (--this.itemInUseCount == 0 && !this.worldObj.client)
                {
                    this.onItemUseFinish();
                }
            }
            else
            {
                this.clearItemInUse();
            }
        }

        if (this.xpCooldown > 0)
        {
            --this.xpCooldown;
        }
        
        this.updateNpc();
//        super.onUpdate();

        if (!this.worldObj.client && this.openContainer != null && !this.openContainer.canInteractWith(this))
        {
            this.closeScreen();
            this.openContainer = this.inventoryContainer;
        }

        this.prevChasingPosX = this.chasingPosX;
        this.prevChasingPosY = this.chasingPosY;
        this.prevChasingPosZ = this.chasingPosZ;
        double d5 = this.posX - this.chasingPosX;
        double d0 = this.posY - this.chasingPosY;
        double d1 = this.posZ - this.chasingPosZ;
        double d2 = 10.0D;

        if (d5 > d2)
        {
            this.prevChasingPosX = this.chasingPosX = this.posX;
        }

        if (d1 > d2)
        {
            this.prevChasingPosZ = this.chasingPosZ = this.posZ;
        }

        if (d0 > d2)
        {
            this.prevChasingPosY = this.chasingPosY = this.posY;
        }

        if (d5 < -d2)
        {
            this.prevChasingPosX = this.chasingPosX = this.posX;
        }

        if (d1 < -d2)
        {
            this.prevChasingPosZ = this.chasingPosZ = this.posZ;
        }

        if (d0 < -d2)
        {
            this.prevChasingPosY = this.chasingPosY = this.posY;
        }

        this.chasingPosX += d5 * 0.25D;
        this.chasingPosZ += d1 * 0.25D;
        this.chasingPosY += d0 * 0.25D;

//        if (this.vehicle == null)
//        {
//            this.startMinecartRidingCoordinate = null;
//        }

//        if (!this.worldObj.client)
//        {
//            this.triggerAchievement(StatRegistry.minutesPlayedStat);

//            if (this.isEntityAlive())
//            {
//                this.triggerAchievement(StatRegistry.timeSinceDeathStat);
//            }
//        }

        double d3 = ExtMath.clampd(this.posX, -World.MAX_SIZE + 1, World.MAX_SIZE - 1);
        double d4 = ExtMath.clampd(this.posZ, -World.MAX_SIZE + 1, World.MAX_SIZE - 1);

        if (d3 != this.posX || d4 != this.posZ)
        {
            this.setPosition(d3, this.posY, d4);
        }
    }

    /**
     * Called when player presses the drop item key
     */
    public EntityItem dropOneItem(boolean dropAll)
    {
    	if(this.client != null) {
	        CPacketBreak.Action c07packetplayerdigging$action = dropAll ? CPacketBreak.Action.DROP_ALL_ITEMS : CPacketBreak.Action.DROP_ITEM;
	        this.client.addToSendQueue(new CPacketBreak(c07packetplayerdigging$action, BlockPos.ORIGIN, Facing.DOWN));
	        return null;
    	}
        return this.dropItem(this.inventory.decrStackSize(this.inventory.currentItem, dropAll && this.inventory.getCurrentItem() != null ? this.inventory.getCurrentItem().stackSize : 1), false, true);
    }

    /**
     * Joins the passed in entity item with the world. Args: entityItem
     */
    protected void joinEntityItemWithWorld(EntityItem itemIn)
    {
    	if(this.client == null)
            this.worldObj.spawnEntityInWorld(itemIn);
    }

    protected void changeSize(float width, float height) {
    	super.changeSize(width, height);
    	if(this.client != null)
    		this.stepHeight = height / 3.0f;
    }

    /**
     * Swings the item the player is holding.
     */
    public void swingItem()
    {
        super.swingItem();
        if(this.client != null)
    		this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.SWING_ARM));
    }

    /**
     * Deals damage to the entity. If its a EntityNPC then will take damage from the armor first and then health
     * second with the reduced value. Args: damageAmount
     */
    protected void damageEntity(DamageSource damageSrc, int damageAmount)
    {
    	if(this.client != null) {
//	        if(!this.isEntityInvulnerable(damageSrc))
	        this.setHealth(this.getHealth() - damageAmount);
	        return;
    	}
    	if(!this.isPlayer()) {
    		super.damageEntity(damageSrc, damageAmount);
    		return;
    	}

//        if (!this.isEntityInvulnerable(damageSrc))
//        {
        if (!damageSrc.isUnblockable() && this.isBlocking() && damageAmount > 0)
        {
            damageAmount = (1 + damageAmount) / 2;
        }

        damageAmount = this.applyArmorCalculations(damageSrc, damageAmount);
        damageAmount = this.applyPotionDamageCalculations(damageSrc, damageAmount);
        int f = damageAmount;
        damageAmount = Math.max(damageAmount - this.getAbsorptionAmount(), 0);
        this.setAbsorptionAmount(this.getAbsorptionAmount() - (f - damageAmount));

        if (damageAmount != 0)
        {
//                float f1 = this.getHealth();
            this.setHealth(this.getHealth() - damageAmount);
            this.trackDamage(damageSrc, damageAmount);

//                if ((float)damageAmount < 3.4028235E37F)
//                {
//                if(damageAmount < Integer.MAX_VALUE)
//                	this.addStat(StatRegistry.damageTakenStat, damageAmount);
//                }
        }
//        }
    }

    /**
     * set current crafting inventory back to the 2x2 square
     */
    public void closeScreen()
    {
		if(this.connection != null)
    		this.connection.closeScreen();
		else if(this.client != null) {
//			this.setScreenClosed();
//	        this.sendQueue.addToSendQueue(new CPacketAction(CPacketAction.Action.CLOSE_CONTAINER)); // , this.openContainer.windowId));
//	        this.closeScreenAndDropStack();
			this.client.closeGui();
		}
		else
			this.openContainer = this.inventoryContainer;
    }
    
    public void setScreenClosed() {
    	if(this.client != null) {
	    	this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.CLOSE_CONTAINER, this.openContainer.windowId));
	        this.inventory.setItemStack((ItemStack)null);
	        this.openContainer = this.inventoryContainer;
    	}
    }

    protected boolean pushOutOfBlocks(double x, double y, double z)
    {
    	if(this.client == null)
    		return super.pushOutOfBlocks(x, y, z);
        if (this.noClip)
        {
            return false;
        }
        else
        {
            BlockPos blockpos = new BlockPos(x, y, z);
            double d0 = x - (double)blockpos.getX();
            double d1 = z - (double)blockpos.getZ();

            if (!this.isOpenBlockSpace(blockpos))
            {
                int i = -1;
                double d2 = 9999.0D;

                if (this.isOpenBlockSpace(blockpos.west()) && d0 < d2)
                {
                    d2 = d0;
                    i = 0;
                }

                if (this.isOpenBlockSpace(blockpos.east()) && 1.0D - d0 < d2)
                {
                    d2 = 1.0D - d0;
                    i = 1;
                }

                if (this.isOpenBlockSpace(blockpos.north()) && d1 < d2)
                {
                    d2 = d1;
                    i = 4;
                }

                if (this.isOpenBlockSpace(blockpos.south()) && 1.0D - d1 < d2)
                {
                    d2 = 1.0D - d1;
                    i = 5;
                }

                float f = 0.1F;

                if (i == 0)
                {
                    this.motionX = (double)(-f);
                }

                if (i == 1)
                {
                    this.motionX = (double)f;
                }

                if (i == 4)
                {
                    this.motionZ = (double)(-f);
                }

                if (i == 5)
                {
                    this.motionZ = (double)f;
                }
            }

            return false;
        }
    }

    /**
     * Set sprinting switch for Entity.
     */
    public void setSprinting(boolean sprinting)
    {
        super.setSprinting(sprinting);
        if(this.client != null)
    		this.sprintingTicksLeft = sprinting ? 600 : 0;
    }

    public void playSound(SoundEvent name, float volume)
    {
		if(this.connection != null)
    		this.connection.playSound(name, volume);
		else if(this.client != null)
    		((AWorldClient)this.worldObj).playSound(this.posX, this.posY, this.posZ, name, volume);
		else if(!this.slave)
			super.playSound(name, volume);
    }
    
    public boolean isTicked()
    {
        return (!this.worldObj.client && (Config.mobTick || this.connection != null)) || this.client != null;
    }

    public void openEditSign(TileEntitySign signTile)
    {
    	if(this.connection != null)
    		this.connection.openEditSign(signTile);
    	else if(this.client != null)
    		this.client.displayGuiSign(signTile.getPos(), signTile.signText);
    }

    /**
     * Displays the GUI for interacting with a book.
     */
//    public void displayGUIBook(ItemStack bookStack)
//    {
//		if(this.connection != null)
//    		this.connection.displayGUIBook(bookStack);
//		else if(this.sendQueue != null) {
//	        Item item = bookStack.getItem();
//	
//	        if (item == Items.writable_book)
//	        {
//	            this.gm.displayGuiScreen(new GuiBook(bookStack));
//	        }
//		}
//    }

    /**
     * Displays the GUI for interacting with a chest inventory. Args: chestInventory
     */
    public void displayGUIChest(IInventory chestInventory)
    {
		if(this.connection != null)
    		this.connection.displayGUIChest(chestInventory);
		else if(this.client != null) {
	        this.client.displayGUIChest(chestInventory, this.inventory);
		}
    }

    public void displayGUIHorse(EntityHorse horse, IInventory horseInventory)
    {
		if(this.connection != null)
    		this.connection.displayGUIHorse(horse, horseInventory);
		else if(this.client != null)
			this.client.displayGuiHorse(horse, this.inventory, horseInventory);
    }

    public void displayGui(IInteractionObject guiOwner)
    {
		if(this.connection != null)
    		this.connection.displayGui(guiOwner);
		else if(this.client != null) {
	        this.client.displayGui(guiOwner, this.inventory, this.worldObj);
		}
    }

    /**
     * Called when the player performs a critical hit on the Entity. Args: entity that was hit critically
     */
    public void onCriticalHit(Entity entityHit)
    {
		if(this.connection != null)
    		this.connection.onCriticalHit(entityHit);
		else if(this.client != null)
			this.client.emitParticleAtEntity(entityHit, ParticleType.CRIT);
    }

    public void onEnchantmentCritical(Entity entityHit)
    {
		if(this.connection != null)
    		this.connection.onEnchantmentCritical(entityHit);
		else if(this.client != null)
			this.client.emitParticleAtEntity(entityHit, ParticleType.CRIT_MAGIC);
    }

    /**
     * Returns if this entity is sneaking.
     */
    public boolean isSneaking()
    {
        return this.client != null ? this.client.isSneaking() : super.isSneaking();
    }

    public void updateEntityActionState()
    {
    	if(!this.isPlayer()) {
    		super.updateEntityActionState();
    		return;
    	}
        this.updateArmSwingProgress();
        this.headYaw = this.rotYaw;
//        super.updateEntityActionState();

        if (this.client != null && this.client.isRenderViewEntity(this))
        {
            this.moveStrafe = this.client.getMoveStrafe();
            this.moveForward = this.client.getMoveForward();
            this.jumping = this.client.isJumping();
            this.prevRenderArmYaw = this.renderArmYaw;
            this.prevRenderArmPitch = this.renderArmPitch;
            this.renderArmPitch = (float)((double)this.renderArmPitch + (double)(this.rotPitch - this.renderArmPitch) * 0.5D);
            this.renderArmYaw = (float)((double)this.renderArmYaw + (double)(this.rotYaw - this.renderArmYaw) * 0.5D);
        }
    }

    /**
     * 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.
     */
    public void onLivingUpdate()
    {
    	if(this.client != null) {
	        if (this.sprintingTicksLeft > 0)
	        {
	            --this.sprintingTicksLeft;
	
	            if (this.sprintingTicksLeft == 0)
	            {
	                this.setSprinting(false);
	            }
	        }
	
	        if (this.sprintToggleTimer > 0)
	        {
	            --this.sprintToggleTimer;
	        }
	
//	        this.prevNausea = this.nausea;
	
	//        if (this.inStandingPortal)
	//        {
	//            if (this.gm.openGui != null && !this.gm.openGui.doesGuiPauseGame())
	//            {
	//                this.gm.displayGuiScreen((GuiScreen)null);
	//            }
	//
	////            if (this.timeInPortal == 0.0F)
	////            {
	////                this.gm.getSoundHandler().playSound(new PositionedSoundRecord("portal.trigger", this.rand.floatv() * 0.4F + 0.8F));
	////            }
	//
	////            this.timeInPortal += 0.0125F;
	////
	////            if (this.timeInPortal >= 1.0F)
	////            {
	////                this.timeInPortal = 1.0F;
	////            }
	//
	//            this.inStandingPortal = false;
	//        }
//	        if (this.hasEffect(Potion.confusion) && this.getEffect(Potion.confusion).getDuration() > 60)
//	        {
//	            this.nausea += 0.006666667F;
//	
//	            if (this.nausea > 1.0F)
//	            {
//	                this.nausea = 1.0F;
//	            }
//	        }
//	        else
//	        {
//	            if (this.nausea > 0.0F)
//	            {
//	                this.nausea -= 0.05F;
//	            }
//	
//	            if (this.nausea < 0.0F)
//	            {
//	                this.nausea = 0.0F;
//	            }
//	        }
	
	//        if (this.portalTimer > 0)
	//        {
	//            --this.portalTimer;
	//        }
	
	        boolean flag = this.client.isJumping();
	        boolean flag1 = this.client.isSneaking();
	        float f = 0.8F;
	        boolean flag2 = this.client.getMoveForward() >= f;
	        this.client.updatePlayerMoveState();
	
	        if (this.isUsingItem() && !this.isRiding())
	        {
	            this.client.setMoveStrafe(this.client.getMoveStrafe() * 0.2F);
	            this.client.setMoveForward(this.client.getMoveForward() * 0.2F);
	            this.sprintToggleTimer = 0;
	        }
	
	        this.pushOutOfBlocks(this.posX - (double)this.width * 0.35D, this.getEntityBoundingBox().minY + 0.5D, this.posZ + (double)this.width * 0.35D);
	        this.pushOutOfBlocks(this.posX - (double)this.width * 0.35D, this.getEntityBoundingBox().minY + 0.5D, this.posZ - (double)this.width * 0.35D);
	        this.pushOutOfBlocks(this.posX + (double)this.width * 0.35D, this.getEntityBoundingBox().minY + 0.5D, this.posZ - (double)this.width * 0.35D);
	        this.pushOutOfBlocks(this.posX + (double)this.width * 0.35D, this.getEntityBoundingBox().minY + 0.5D, this.posZ + (double)this.width * 0.35D);
	        boolean canSprint = true; // (float)this.getFoodStats().getFoodLevel() > 6.0F || this.allowFlying;
	
	        if (this.onGround && !flag1 && !flag2 && this.client.getMoveForward() >= f && !this.isSprinting() && canSprint && !this.isUsingItem() && !this.hasEffect(Potion.BLINDNESS))
	        {
	            if (this.sprintToggleTimer <= 0 && !this.client.isSprinting())
	            {
	                this.sprintToggleTimer = 7;
	            }
	            else
	            {
	                this.setSprinting(true);
	            }
	        }
	
	        if (!this.isSprinting() && this.client.getMoveForward() >= f && canSprint && !this.isUsingItem() && !this.hasEffect(Potion.BLINDNESS) && this.client.isSprinting())
	        {
	            this.setSprinting(true);
	        }
	
	        if (this.isSprinting() && (this.client.getMoveForward() < f || this.collidedHorizontally || !canSprint))
	        {
	            this.setSprinting(false);
	        }
	
	        if (this.hasEffect(Potion.FLYING) || this.noclip || this.canNaturallyFly())
	        {
	            if (this.noclip)
	            {
	                if (!this.flying)
	                {
	                    this.flying = true;
	                    this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.START_FLYING));
	                }
	            }
	            else if (!flag && this.client.isJumping())
	            {
	                if (this.flyToggleTimer == 0)
	                {
	                    this.flyToggleTimer = 7;
	                }
	                else
	                {
	                    this.flying = !this.flying;
	                    this.client.addToSendQueue(new CPacketAction(this.flying ? 
	                    		CPacketAction.Action.START_FLYING : CPacketAction.Action.STOP_FLYING));
	                    this.flyToggleTimer = 0;
	                }
	            }
	        }
	        else { // if(!this.firstEffectUpdate) {
	        	this.flying = false;
	        }
	//        this.firstEffectUpdate = false;
	
	        if (this.isFlying() && this.client.isRenderViewEntity(this))
	        {
	            if (this.client.isSneaking())
	            {
	                this.motionY -= (double)(
	                		this.landMovement * 0.5f * (this.canFlyFullSpeed() ? 3.0F : 1.0F));
	            }
	
	            if (this.client.isJumping())
	            {
	                this.motionY += (double)(
	                		this.landMovement * 0.5f * (this.canFlyFullSpeed() ? 3.0F : 1.0F));
	            }
	        }
	
	        if (this.isRidingHorse())
	        {
	            if (this.horseJumpPowerCounter < 0)
	            {
	                ++this.horseJumpPowerCounter;
	
	                if (this.horseJumpPowerCounter == 0)
	                {
	                    this.horseJumpPower = 0.0F;
	                }
	            }
	
	            if (flag && !this.client.isJumping())
	            {
	                this.horseJumpPowerCounter = -10;
	                this.sendHorseJump();
	            }
	            else if (!flag && this.client.isJumping())
	            {
	                this.horseJumpPowerCounter = 0;
	                this.horseJumpPower = 0.0F;
	            }
	            else if (flag)
	            {
	                ++this.horseJumpPowerCounter;
	
	                if (this.horseJumpPowerCounter < 10)
	                {
	                    this.horseJumpPower = (float)this.horseJumpPowerCounter * 0.1F;
	                }
	                else
	                {
	                    this.horseJumpPower = 0.8F + 2.0F / (float)(this.horseJumpPowerCounter - 9) * 0.1F;
	                }
	            }
	        }
	        else
	        {
	            this.horseJumpPower = 0.0F;
	        }
	
	        this.onPlayerUpdate();
//	        super.onLivingUpdate();
	
	        if (this.onGround && this.flying && !this.noclip)
	        {
	            this.flying = false;
	            this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.STOP_FLYING));
	        }
	        return;
    	}

    	if(this.slave) {
	        if (this.otherPlayerMPPosRotationIncrements > 0)
	        {
	            double d0 = this.posX + (this.otherPlayerMPX - this.posX) / (double)this.otherPlayerMPPosRotationIncrements;
	            double d1 = this.posY + (this.otherPlayerMPY - this.posY) / (double)this.otherPlayerMPPosRotationIncrements;
	            double d2 = this.posZ + (this.otherPlayerMPZ - this.posZ) / (double)this.otherPlayerMPPosRotationIncrements;
	            double d3;
	
	            for (d3 = this.otherPlayerMPYaw - (double)this.rotYaw; d3 < -180.0D; d3 += 360.0D)
	            {
	                ;
	            }
	
	            while (d3 >= 180.0D)
	            {
	                d3 -= 360.0D;
	            }
	
	            this.rotYaw = (float)((double)this.rotYaw + d3 / (double)this.otherPlayerMPPosRotationIncrements);
	            this.rotPitch = (float)((double)this.rotPitch + (this.otherPlayerMPPitch - (double)this.rotPitch) / (double)this.otherPlayerMPPosRotationIncrements);
	            --this.otherPlayerMPPosRotationIncrements;
	            this.setPosition(d0, d1, d2);
	            this.setRotation(this.rotYaw, this.rotPitch);
	        }
	
	        this.prevCameraYaw = this.cameraYaw;
	        this.updateArmSwingProgress();
	        float f1 = ExtMath.sqrtd(this.motionX * this.motionX + this.motionZ * this.motionZ);
	        float f = (float)Math.atan(-this.motionY * 0.20000000298023224D) * 15.0F;
	
	        if (f1 > 0.1F)
	        {
	            f1 = 0.1F;
	        }
	
	        if (!this.onGround || this.getHealth() <= 0)
	        {
	            f1 = 0.0F;
	        }
	
	        if (this.onGround || this.getHealth() <= 0)
	        {
	            f = 0.0F;
	        }
	
	        this.cameraYaw += (f1 - this.cameraYaw) * 0.4F;
	        this.camPitch += (f - this.camPitch) * 0.8F;
	        return;
    	}
    	
    	if(this.connection != null) {
    		this.onPlayerUpdate();
    	}
    	else {
//    		if(!(this.isPlayer()))
    		this.updateArmSwingProgress();
    		this.onNpcUpdate();
    	}
    }
    
    private void onPlayerUpdate() {
    	if (this.flyToggleTimer > 0)
        {
            --this.flyToggleTimer;
        }

        if (!this.worldObj.client && this.sinceLastAttack < Integer.MAX_VALUE)
        {
            ++this.sinceLastAttack;
        }

//        this.inventory.decrementAnimations();
        this.prevCameraYaw = this.cameraYaw;
//        super.onLivingUpdate();
        this.onNpcUpdate();
        AttributeInstance iattributeinstance = this.getEntityAttribute(Attributes.MOVEMENT_SPEED);

        this.jumpMovement = this.speedInAir;

        if (this.isSprinting())
        {
            this.jumpMovement = (float)((double)this.jumpMovement + (double)this.speedInAir * 0.3D);
        }

        this.setAIMoveSpeed((float)iattributeinstance.getAttributeValue());
        float f = ExtMath.sqrtd(this.motionX * this.motionX + this.motionZ * this.motionZ);
        float f1 = (float)(Math.atan(-this.motionY * 0.20000000298023224D) * 15.0D);

        if (f > 0.1F)
        {
            f = 0.1F;
        }

        if (!this.onGround || this.getHealth() <= 0)
        {
            f = 0.0F;
        }

        if (this.onGround || this.getHealth() <= 0)
        {
            f1 = 0.0F;
        }

        this.cameraYaw += (f - this.cameraYaw) * 0.4F;
        this.camPitch += (f1 - this.camPitch) * 0.8F;

        if (this.getHealth() > 0 && !this.noclip)
        {
            BoundingBox axisalignedbb = null;

            if (this.vehicle != null && !this.vehicle.dead)
            {
                axisalignedbb = this.getEntityBoundingBox().union(this.vehicle.getEntityBoundingBox()).expand(1.0D, 0.0D, 1.0D);
            }
            else
            {
                axisalignedbb = this.getEntityBoundingBox().expand(1.0D, 0.5D, 1.0D);
            }

            List<Entity> list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, axisalignedbb);

            for (int i = 0; i < list.size(); ++i)
            {
                Entity entity = (Entity)list.get(i);

                if (!entity.dead)
                {
                    this.collideWithPlayer(entity);
                }
            }
        }
    }
    
    // END SP
    
    
    
    // START SP SPEC
    


    /**
     * called every tick when the player is on foot. Performs all the things that normally happen during movement.
     */
    public void onUpdateWalkingPlayer()
    {
        boolean flag = this.isSprinting();

        if (flag != this.serverSprintState)
        {
            if (flag)
            {
                this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.START_SPRINTING));
            }
            else
            {
                this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.STOP_SPRINTING));
            }

            this.serverSprintState = flag;
        }

        boolean flag1 = this.isSneaking();

        if (flag1 != this.serverSneakState)
        {
            if (flag1)
            {
                this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.START_SNEAKING));
            }
            else
            {
                this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.STOP_SNEAKING));
            }

            this.serverSneakState = flag1;
        }

        if (this.client.isRenderViewEntity(this))
        {
            double d0 = this.posX - this.lastReportedPosX;
            double d1 = this.getEntityBoundingBox().minY - this.lastReportedPosY;
            double d2 = this.posZ - this.lastReportedPosZ;
            double d3 = (double)(this.rotYaw - this.lastReportedYaw);
            double d4 = (double)(this.rotPitch - this.lastReportedPitch);
            boolean flag2 = d0 * d0 + d1 * d1 + d2 * d2 > 9.0E-4D || this.positionUpdateTicks >= 20;
            boolean flag3 = d3 != 0.0D || d4 != 0.0D;

            if (this.vehicle == null)
            {
                if (flag2 && flag3)
                {
                    this.client.addToSendQueue(new CPacketPlayer.C06PacketPlayerPosLook(this.posX, this.getEntityBoundingBox().minY, this.posZ, this.rotYaw, this.rotPitch, this.onGround));
                }
                else if (flag2)
                {
                    this.client.addToSendQueue(new CPacketPlayer.C04PacketPlayerPosition(this.posX, this.getEntityBoundingBox().minY, this.posZ, this.onGround));
                }
                else if (flag3)
                {
                    this.client.addToSendQueue(new CPacketPlayer.C05PacketPlayerLook(this.rotYaw, this.rotPitch, this.onGround));
                }
                else
                {
                    this.client.addToSendQueue(new CPacketPlayer(this.onGround));
                }
            }
            else
            {
                this.client.addToSendQueue(new CPacketPlayer.C06PacketPlayerPosLook(this.motionX, -999.0D, this.motionZ, this.rotYaw, this.rotPitch, this.onGround));
                flag2 = false;
            }

            ++this.positionUpdateTicks;

            if (flag2)
            {
                this.lastReportedPosX = this.posX;
                this.lastReportedPosY = this.getEntityBoundingBox().minY;
                this.lastReportedPosZ = this.posZ;
                this.positionUpdateTicks = 0;
            }

            if (flag3)
            {
                this.lastReportedYaw = this.rotYaw;
                this.lastReportedPitch = this.rotPitch;
            }
        }
    }

    public void respawnPlayer()
    {
        this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.PERFORM_RESPAWN));
    }

//    public void closeScreenAndDropStack()
//    {
//        this.inventory.setItemStack((ItemStack)null);
//        this.openContainer = this.inventoryContainer;
////        super.closeScreen();
//        this.gm.displayGuiScreen(null);
//    }

    /**
     * Updates health locally.
     */
    public void setPlayerSPHealth(int health)
    {
        if (this.hasValidHealth)
        {
            int f = this.getHealth() - health;

            if (f <= 0)
            {
                this.setHealth(health);

                if (f < 0)
                {
                    this.hurtResistance = this.hurtCooldown / 2;
                }
            }
            else
            {
                this.lastDamage = f;
                this.setHealth(this.getHealth());
                this.hurtResistance = this.hurtCooldown;
                this.damageEntity(DamageSource.generic, f);
                this.hurtTime = this.maxHurtTime = 10;
            }
        }
        else
        {
            this.setHealth(health);
            this.hasValidHealth = true;
        }
    }

    protected void sendHorseJump()
    {
        this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.RIDING_JUMP, (int)(this.getHorseJumpPower() * 100.0F)));
    }

    public void sendHorseInventory()
    {
        this.client.addToSendQueue(new CPacketAction(CPacketAction.Action.OPEN_INVENTORY));
    }

    /**
     * Returns true if the block at the given BlockPos and the block above it are NOT full cubes.
     */
    private boolean isOpenBlockSpace(BlockPos pos)
    {
        return !this.worldObj.getState(pos).getBlock().isNormalCube() && (this.height <= 1.0f || !this.worldObj.getState(pos.up()).getBlock().isNormalCube());
    }

    /**
     * Sets the current XP, total XP, and level number.
     */
    public void setXPStats(float currentXP, int maxXP, int level)
    {
        this.experience = currentXP;
        this.experienceTotal = maxXP;
        this.experienceLevel = level;
    }

    public boolean isRidingHorse()
    {
        return this.vehicle != null && this.vehicle instanceof EntityHorse && ((EntityHorse)this.vehicle).isHorseSaddled();
    }

    public float getHorseJumpPower()
    {
        return this.horseJumpPower;
    }

    public void displayTradeGui(String title)
    {
        this.client.displayGuiMerchant(title, this.inventory, this.worldObj);
    }

    
    
    // END SP SPEC
    
    // START OTHER

    public void setPositionAndRotation2(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean p_180426_10_)
    {
    	if(this.slave && this.client == null) {
	        this.otherPlayerMPX = x;
	        this.otherPlayerMPY = y;
	        this.otherPlayerMPZ = z;
	        this.otherPlayerMPYaw = (double)yaw;
	        this.otherPlayerMPPitch = (double)pitch;
	        this.otherPlayerMPPosRotationIncrements = posRotationIncrements;
    	}
    	else {
    		super.setPositionAndRotation2(x, y, z, yaw, pitch, posRotationIncrements, p_180426_10_);
    	}
    }
    
    public void setItem(int slot, ItemStack stack)
    {
    	if(this.slave && this.client == null) {
	        if (slot == 0)
	            this.inventory.mainInventory[this.inventory.currentItem] = stack;
	        else
	            this.inventory.armorInventory[slot - 1] = stack;
    	}
    	else if(this.isPlayer()) {
    		this.inventory.armorInventory[slot] = stack;
    	}
    	else {
            this.setItemNoUpdate(slot, stack);
            if(!this.worldObj.client && slot == 0)
                this.setCombatTask();
    	}
    }
    
    // END OTHER
    
    
    // START MP

	public void addExperienceLevel(int levels) {
        this.experienceLevel += levels;

        if (this.experienceLevel < 0)
        {
            this.experienceLevel = 0;
            this.experience = 0.0F;
            this.experienceTotal = 0;
        }

        if (levels > 0 && this.experienceLevel % 5 == 0 && (float)this.lastXPSound < (float)this.ticksExisted - 100.0F)
        {
            float f = this.experienceLevel > 30 ? 1.0F : (float)this.experienceLevel / 30.0F;
            this.worldObj.playSoundAtEntity(this, SoundEvent.LEVELUP, f * 0.75F);
            this.lastXPSound = this.ticksExisted;
        }
//		super.addExperienceLevel(levels);
		if(this.connection != null)
    		this.connection.resetLastExperience();
	}

	public void removeExperienceLevel(int levels) {
        this.experienceLevel -= levels;

        if (this.experienceLevel < 0)
        {
            this.experienceLevel = 0;
            this.experience = 0.0F;
            this.experienceTotal = 0;
        }

        this.xpSeed = this.rand.intv();
//		super.removeExperienceLevel(levels);
		if(this.connection != null)
    		this.connection.resetLastExperience();
	}

	public void onDeath(DamageSource cause) {
		if(this.connection != null) {
			this.connection.onEntityDeath();
			return;
		}
		if(!this.isPlayer()) {
			super.onDeath(cause);
			return;
		}

        this.noPickup = true;
        super.onDeath(cause);
        if(this.slave) {
	        this.changeSize(0.2F, 0.2F);
	        this.setPosition(this.posX, this.posY, this.posZ);
	        this.motionY = 0.10000000149011612D;
	
	        if (this.worldObj.client || (!Config.keepInventory && Config.playerDrop))
	        {
	            this.inventory.dropAllItems();
	        }
	
	        if (cause != null)
	        {
	            this.motionX = (double)(-ExtMath.cos((this.attackedYaw + this.rotYaw) * (float)Math.PI / 180.0F) * 0.1F);
	            this.motionZ = (double)(-ExtMath.sin((this.attackedYaw + this.rotYaw) * (float)Math.PI / 180.0F) * 0.1F);
	        }
	        else
	        {
	            this.motionX = this.motionZ = 0.0D;
	        }
	
//	        this.triggerAchievement(StatRegistry.deathsStat);
//	        this.removeStat(StatRegistry.timeSinceDeathStat);
        }
	}

	public Entity travelToDimension(int dimensionId, BlockPos pos, float yaw, float pitch, PortalType portal) {
		if(this.connection != null)
    		this.connection.travelToDimension(dimensionId, pos, yaw, pitch, portal);
		return this.isPlayer() ? this : super.travelToDimension(dimensionId, pos, yaw, pitch, portal);
	}

	public void teleport(double x, double y, double z, float yaw, float pitch, int dimension) {
		if(this.connection != null)
    		this.connection.teleport(x, y, z, yaw, pitch, dimension);
		else if(!this.isPlayer())
			super.teleport(x, y, z, yaw, pitch, dimension);
	}

	public void onItemPickup(Entity entity, int amount) {
		super.onItemPickup(entity, amount);
		if(this.connection != null)
    		this.connection.onItemPickup(entity, amount);
	}

	protected void updateFallState(double y, boolean onGroundIn, Block blockIn, BlockPos pos) {
    	if(this.connection == null)
    		super.updateFallState(y, onGroundIn, blockIn, pos);
	}

	public void addStat(int amount) {
//		if(this.connection != null)
//    		this.connection.addStat(amount);
	}

//	public void removeStat(StatBase stat) {
//		if(this.connection != null)
//    		this.connection.removeStat(stat);
//	}

	protected void onItemUseFinish() {
		if(this.connection != null)
    		this.connection.onItemUseFinish();
//		super.onItemUseFinish();
        if (this.itemInUse != null)
        {
            this.updateItemUse(this.itemInUse, 16);
            int i = this.itemInUse.stackSize;
            ItemStack itemstack = this.itemInUse.onItemUseFinish(this.worldObj, this);

            if (itemstack != this.itemInUse || itemstack != null && itemstack.stackSize != i)
            {
                this.inventory.mainInventory[this.inventory.currentItem] = itemstack;

                if (itemstack.stackSize == 0)
                {
                    this.inventory.mainInventory[this.inventory.currentItem] = null;
                }
            }

            this.clearItemInUse();
        }
	}

	protected void onNewEffect(PotionEffect id) {
		super.onNewEffect(id);
		if(this.connection != null)
    		this.connection.onNewEffect(id);
	}

	protected void onChangedEffect(PotionEffect id, boolean added) {
		super.onChangedEffect(id, added);
		if(this.connection != null)
    		this.connection.onChangedEffect(id, added);
	}

	protected void onFinishedEffect(PotionEffect effect) {
        super.onFinishedEffect(effect);
        if(this.isPlayer() && effect.getPotion() == Potion.FLYING && !this.noclip && !this.canNaturallyFly())
        	this.flying = false;
//		super.onFinishedEffect(effect);
        if(this.connection != null)
    		this.connection.onFinishedEffect(effect);
	}

	public void setPositionAndUpdate(double x, double y, double z) {
		if(this.connection != null)
    		this.connection.setPositionAndUpdate(x, y, z);
		else
			super.setPositionAndUpdate(x, y, z);
	}

	public void updateEffectMeta() {
		super.updateEffectMeta();
		if(this.connection != null)
    		this.connection.updateEffectMeta();
	}

	public final AWorldServer getServerWorld() {
		return (AWorldServer)this.worldObj;
	}

	public void onUpdateEntity() {
//		super.onUpdate();
		this.updatePlayer();
	}

	public void updateEntityFall(double y, boolean onGroundIn, Block blockIn, BlockPos pos) {
		super.updateFallState(y, onGroundIn, blockIn, pos);
	}
    
    // END MP
	
	
	// START PLAYER
    
    public boolean isOnLadder()
    {
    	return (!this.isPlayer() || !this.noclip) && super.isOnLadder();
    }

//    protected void applyEntityAttributes()
//    {
//        super.applyEntityAttributes();
//    }

    protected void entityInit()
    {
        super.entityInit();
        this.dataWatcher.addObject(16, "");
        this.dataWatcher.addObject(17, "");
        this.dataWatcher.addObject(18, Byte.valueOf((byte)Alignment.NEUTRAL.ordinal()));
//        this.dataWatcher.addObject(20, Byte.valueOf((byte)0));
        this.dataWatcher.addObject(21, 0);
        this.dataWatcher.addObject(22, Byte.valueOf((byte)-1));
        this.dataWatcher.addObject(29, 1.0f);
//        super.entityInit();
        this.dataWatcher.addObject(30, Integer.valueOf(0));
//        this.dataWatcher.addObject(10, Integer.valueOf(~ModelPart.ARMS_SLIM.getMask()));
//        this.dataWatcher.addObject(11, Byte.valueOf((byte)0));
    }

    /**
     * returns the ItemStack containing the itemInUse
     */
    public ItemStack getItemInUse()
    {
        return this.itemInUse;
    }

    /**
     * Returns the item in use count
     */
    public int getItemInUseCount()
    {
        return this.itemInUseCount;
    }

    /**
     * Checks if the entity is currently using an item (e.g., bow, food, sword) by holding down the useItemButton
     */
    public boolean isUsingItem()
    {
        return this.isPlayer() ? this.itemInUse != null : this.getFlag(4);
    }

    /**
     * gets the duration for how long the current itemInUse has been in use
     */
    public int getItemInUseDuration()
    {
        return this.isUsingItem() ? this.itemInUse.getMaxItemUseDuration() - this.itemInUseCount : 0;
    }

    public void stopUsingItem()
    {
        if (this.itemInUse != null)
        {
            this.itemInUse.onPlayerStoppedUsing(this.worldObj, this, this.itemInUseCount);
        }

        this.clearItemInUse();
    }

    public void clearItemInUse()
    {
        this.itemInUse = null;
        this.itemInUseCount = 0;

        if (!this.worldObj.client)
        {
            this.setUsingItem(false);
        }
    }

    public boolean isBlocking()
    {
        return this.isUsingItem() && this.itemInUse.getItem().getItemUseAction(this.itemInUse) == ItemAction.BLOCK;
    }

    /**
     * Plays sounds and makes particles for item in use state
     */
    protected void updateItemUse(ItemStack itemStackIn, int p_71010_2_)
    {
        if (itemStackIn.getItemUseAction() == ItemAction.DRINK)
        {
            this.playSound(SoundEvent.DRINK, 0.5F);
        }

        if (itemStackIn.getItemUseAction() == ItemAction.EAT)
        {
            this.playSound(SoundEvent.EAT, 0.5F + 0.5F * (float)this.rand.zrange(2));
        }
    }

    public void handleStatusUpdate(byte id)
    {
        if (this.isPlayer() && id == 9)
        {
            this.onItemUseFinish();
        }
        else if (id == 12)
        {
            this.spawnParticles(ParticleType.HEART);
        }
        else if (id == 13)
        {
            this.spawnParticles(ParticleType.SMOKE_NORMAL);
        }
        else
        {
            super.handleStatusUpdate(id);
        }
    }

//    /**
//     * Dead and sleeping entities cannot move
//     */
//    protected boolean isMovementBlocked()
//    {
//        return this.getHealth() <= 0; // || this.isPlayerSleeping();
//    }

    /**
     * Handles updating while being ridden by an entity
     */
    public void updateRidden()
    {
    	if(!this.isPlayer()) {
    		super.updateRidden();
    		return;
    	}
        if (!this.worldObj.client && this.isSneaking())
        {
            this.mountEntity((Entity)null);
            this.setSneaking(false);
        }
        else
        {
            double d0 = this.posX;
            double d1 = this.posY;
            double d2 = this.posZ;
            float f = this.rotYaw;
            float f1 = this.rotPitch;
            super.updateRidden();
            this.prevCameraYaw = this.cameraYaw;
            this.cameraYaw = 0.0F;
            this.addMountedMovementStat(this.posX - d0, this.posY - d1, this.posZ - d2);

            if (this.vehicle instanceof EntityPig)
            {
                this.rotPitch = f1;
                this.rotYaw = f;
                this.yawOffset = ((EntityPig)this.vehicle).yawOffset;
            }
        }
    }

    /**
     * Keeps moving the entity up so it isn't colliding with blocks and other requirements for this entity to be spawned
     * (only actually used on players though its also on Entity)
     */
    public void preparePlayerToSpawn()
    {
    	if(this.isPlayer()) {
			this.updateSize();
	        super.preparePlayerToSpawn();
	        this.setHealth(this.getMaxHealth());
	        this.deathTime = 0;
    	}
    	else {
    		super.preparePlayerToSpawn();
    	}
    }
    
    public void onDataWatcherUpdate(int data) {
    	if(this.isPlayer() && data == 29) // (data == 29 || data == 11)) // && this.worldObj.client)
    		this.updateSize();
    }
    
    private void updateSize() {
//    	ModelType model = this.getModel();
//    	this.changeSize(this.getHeight() * this.species.renderer.width / this.species.renderer.height, this.getHeight());
    	this.changeSize(this.getHeight() / this.species.renderer.height * this.species.renderer.width, this.getHeight());
    }
    
    public double getReachDistance()
    {
        return Math.max(1.5, 5.0 * (double)this.height / 1.8);
    }
    
    public float getRenderScale()
    {
        return /* this.isPlayer() ? (0.9375f * this.height / this.getModel().height) : ( */ 0.9375f * this.height / this.species.renderer.height; // );
    }

    protected void handleJumpLava()
    {
        this.motionY += 0.03999999910593033D * (this.height /* this.getHeight() * 1.8f */ + 2.2f) / 4.0f;
    }

    protected float getJumpUpwardsMotion()
    {
        return 0.42F * (this.height /* this.getHeight() * 1.8f */ + 2.2f) / 4.0f;
    }
    
    public void setAIMoveSpeed(float speedIn)
    {
        this.landMovement = speedIn;
        if(!this.isPlayer())
        	this.setMoveForward(speedIn);
    }

    private void collideWithPlayer(Entity p_71044_1_)
    {
        p_71044_1_.onCollideWithPlayer(this);
    }

    /**
     * Args: itemstack, flag
     */
    public EntityItem dropPlayerItemWithRandomChoice(ItemStack itemStackIn, boolean traceItem)
    {
        return this.dropItem(itemStackIn, false, traceItem);
    }

    public EntityItem dropItem(ItemStack droppedItem, boolean dropAround, boolean traceItem)
    {
        if (droppedItem == null)
        {
            return null;
        }
        else if (droppedItem.stackSize == 0)
        {
            return null;
        }
        else
        {
        	if(traceItem && !this.worldObj.client)
        		this.connection.sendThrowMessage(droppedItem);
        	
            double d0 = this.posY - 0.30000001192092896D + (double)this.getEyeHeight();
            EntityItem entityitem = new EntityItem(this.worldObj, this.posX, d0, this.posZ, droppedItem);
            entityitem.setPickupDelay(40);

//            if (traceItem)
//            {
//                entityitem.setThrower(this.getUser());
//            }

            if (dropAround)
            {
                float f = this.rand.floatv() * 0.5F;
                float f1 = this.rand.floatv() * (float)Math.PI * 2.0F;
                entityitem.motionX = (double)(-ExtMath.sin(f1) * f);
                entityitem.motionZ = (double)(ExtMath.cos(f1) * f);
                entityitem.motionY = 0.20000000298023224D;
            }
            else
            {
                float f2 = 0.3F;
                entityitem.motionX = (double)(-ExtMath.sin(this.rotYaw / 180.0F * (float)Math.PI) * ExtMath.cos(this.rotPitch / 180.0F * (float)Math.PI) * f2);
                entityitem.motionZ = (double)(ExtMath.cos(this.rotYaw / 180.0F * (float)Math.PI) * ExtMath.cos(this.rotPitch / 180.0F * (float)Math.PI) * f2);
                entityitem.motionY = (double)(-ExtMath.sin(this.rotPitch / 180.0F * (float)Math.PI) * f2 + 0.1F);
                float f3 = this.rand.floatv() * (float)Math.PI * 2.0F;
                f2 = 0.02F * this.rand.floatv();
                entityitem.motionX += Math.cos((double)f3) * (double)f2;
                entityitem.motionY += (double)((this.rand.floatv() - this.rand.floatv()) * 0.1F);
                entityitem.motionZ += Math.sin((double)f3) * (double)f2;
            }

            this.joinEntityItemWithWorld(entityitem);

//            if (traceItem)
//            {
//                this.triggerAchievement(StatRegistry.dropStat);
//            }

            return entityitem;
        }
    }

    /**
     * Block hardness will be further counted in game/block/Block.getPlayerRelativeBlockHardness
     */
    public float getToolDigEfficiency(Block p_180471_1_)
    {
        float f = this.inventory.getStrVsBlock(p_180471_1_);

        if (f > 1.0F)
        {
            int i = EnchantmentHelper.getEfficiencyModifier(this);
            ItemStack itemstack = this.inventory.getCurrentItem();

            if (i > 0 && itemstack != null)
            {
                f += (float)(i * i + 1);
            }
        }

        if (this.hasEffect(Potion.HASTE))
        {
        	int speed = this.getEffect(Potion.HASTE).getAmplifier();
        	if(speed >= 255)
        		return 1000000.0f;
            f *= 1.0F + (float)(speed + 1) * 0.2F;
        }

        if (this.hasEffect(Potion.FATIGUE))
        {
            float f1 = 1.0F;

            switch (this.getEffect(Potion.FATIGUE).getAmplifier())
            {
                case 0:
                    f1 = 0.3F;
                    break;

                case 1:
                    f1 = 0.09F;
                    break;

                case 2:
                    f1 = 0.0027F;
                    break;

                case 3:
                default:
                    f1 = 8.1E-4F;
            }

            f *= f1;
        }

        return f;
    }

    /**
     * Checks if the player has the ability to harvest a block (checks current inventory item for a tool if necessary)
     */
    public boolean canHarvestBlock(Block blockToHarvest)
    {
        return this.inventory.canHeldItemHarvest(blockToHarvest);
    }

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

//		if(tagCompund.hasKey("CanPickUpLoot", 1)) {
//			this.setCanPickUpLoot(tagCompund.getBoolean("CanPickUpLoot"));
//		}

		if(tagCompund.hasKey("Equipment", 9)) {
			NBTTagList nbttaglist = tagCompund.getTagList("Equipment", 10);

			for(int i = 0; i < this.equipment.length; ++i) {
				this.equipment[i] = ItemStack.loadItemStackFromNBT(nbttaglist.getCompoundTagAt(i));
			}
		}
//        this.setSpecies(tagCompund.getString("Species"));
        this.setChar(tagCompund.getString("Char"));
        this.setCape(tagCompund.getString("Cape"));
        this.isWilling = tagCompund.getBoolean("Willing");
        this.setMating(tagCompund.getBoolean("Mating"));
        Alignment // align;
//        try {
        	align = Alignment.getByName(tagCompund.getString("Align"));
//        }
//        catch(IllegalArgumentException e) {
//        	align = this.getNaturalAlign(this.rand);
//        }
        this.setAlignment(align);
        this.setManaPoints(tagCompund.getInteger("Mana"));
        Enum type = null;
        if(tagCompund.hasKey("ClassType", 8) && this.species != null && this.species.classEnum != null) {
        	type = this.species.classnames.get(tagCompund.getString("ClassType"));
//	        try {
//	        	type = Enum.valueOf(this.species.classEnum, tagCompund.getString("ClassType").toUpperCase());
//	        }
//	        catch(IllegalArgumentException e) {
//	        	type = null;
//	        }
        }
        this.setNpcClass(type);
        this.setHeight(tagCompund.hasKey("Height", 5) ? tagCompund.getFloat("Height") : this.getBaseSize());

        NBTTagList nbttaglist = tagCompund.getTagList("Items", 10);

        for (int i = 0; i < nbttaglist.tagCount(); ++i)
        {
            ItemStack itemstack = ItemStack.loadItemStackFromNBT(nbttaglist.getCompoundTagAt(i));

            if (itemstack != null)
            {
                this.extraInventory.addStack(itemstack);
            }
        }

		if(tagCompund.hasKey("Offers", 10))
			this.trades = new MerchantRecipeList(tagCompund.getCompoundTag("Offers"));
        this.healTimer = tagCompund.getInteger("healTimer");
        if(tagCompund.hasKey("Skin", 7))
			this.skin = tagCompund.getByteArray("Skin");

//        this.setCanPickUpLoot(true);
        this.setCombatTask();
        
        if(this.isPlayer()) {
	//        this.entityUniqueID = getOfflineUUID(this.user);
	        NBTTagList nbttaglist0 = tagCompund.getTagList("Inventory", 10);
	        this.inventory.readFromNBT(nbttaglist0);
	        this.inventory.currentItem = tagCompund.getInteger("SelectedItemSlot");
	//        this.sleeping = tagCompund.getBoolean("Sleeping");
	//        this.sleepTimer = tagCompund.getShort("SleepTimer");
	        this.experience = tagCompund.getFloat("XpP");
	        this.experienceLevel = tagCompund.getInteger("XpLevel");
	        this.experienceTotal = tagCompund.getInteger("XpTotal");
	        this.xpSeed = tagCompund.getInteger("XpSeed");
	
	        if (this.xpSeed == 0)
	        {
	            this.xpSeed = this.rand.intv();
	        }
	
	//        this.setScore(tagCompund.getInteger("Score"));
	//        this.setManaPoints(tagCompund.getInteger("Mana"));
	
	//        if (this.sleeping)
	//        {
	//            this.playerLocation = new BlockPos(this);
	//            this.wakeUpPlayer();
	//        }
	
	        if (tagCompund.hasKey("SpawnX", 99) && tagCompund.hasKey("SpawnY", 99) && tagCompund.hasKey("SpawnZ", 99))
	        {
	            this.spawnPos = new WorldPos(tagCompund.getInteger("SpawnX"), tagCompund.getInteger("SpawnY"), 
	            		tagCompund.getInteger("SpawnZ"), tagCompund.getInteger("SpawnDim"));
	//            this.spawnForced = tagCompund.getBoolean("SpawnForced");
	        }

	        if (tagCompund.hasKey("OriginX", 99) && tagCompund.hasKey("OriginY", 99) && tagCompund.hasKey("OriginZ", 99))
	        {
	            this.originPos = new WorldPos(tagCompund.getInteger("OriginX"), tagCompund.getInteger("OriginY"), 
	            		tagCompund.getInteger("OriginZ"), tagCompund.getInteger("OriginDim"));
	        }
	
	//        this.foodStats.readNBT(tagCompund);
	//        this.readCapabilitiesFromNBT(tagCompund);
	        this.flying = tagCompund.getBoolean("flying") && (this.hasEffect(Potion.FLYING) || this.canNaturallyFly());
	//        if(tagCompund.hasKey("speed", 99))
	//			this.speed = tagCompund.getFloat("speed");
	//        this.disableDamagePersist = tagCompund.getBoolean("alwaysInvulnerable");
	//        this.disableTargetPersist = tagCompund.getBoolean("neverTarget");
	//        this.allowFlyingPersist = tagCompund.getBoolean("alwaysFly");
	        this.noclip = tagCompund.getBoolean("noClip");
	
	        if (tagCompund.hasKey("WarpItems", 9))
	        {
	            NBTTagList nbttaglist1 = tagCompund.getTagList("WarpItems", 10);
	            this.warpChest.loadInventoryFromNBT(nbttaglist1);
	        }
	        
//	        ModelType // model;
	//        try {
//	        	model = ModelType.getByName(tagCompund.getString("Model"));
	//        }
	//        catch(IllegalArgumentException e) {
	//        	model = ModelType.HUMANOID;
	//        }
//	        this.setModel(model);
//	        this.setModelParts(tagCompund.hasKey("PartFlags", 3) ? tagCompund.getInteger("PartFlags") : ~ModelPart.ARMS_SLIM.getMask());
	//        if(tagCompund.hasKey("PlayerScale", 5))
	//        	this.setPlayerHeight(tagCompund.getFloat("PlayerScale"));
        }
    }

    /**
     * (abstract) Protected helper method to write subclass entity data to NBT.
     */
    public void writeEntityToNBT(NBTTagCompound tagCompound)
    {
    	if(this.isPlayer()) {
	        for (int z = 0; z < this.inventory.mainInventory.length; z++)
	        {
	        	ItemStack itemstack = this.inventory.mainInventory[z];
	            if (itemstack != null)
	            {
	                this.getAttributeMap().removeAttributeModifiers(itemstack.getAttributeModifiers(2), z, itemstack.stackSize);
	            }
	        }
    	}
//	    super.writeEntityToNBT(tagCompound);
        super.writeEntityToNBT(tagCompound);

//		tagCompound.setBoolean("CanPickUpLoot", this.canPickUpLoot());
		NBTTagList nbttaglist0 = new NBTTagList();

		for(int i = 0; i < this.equipment.length; ++i) {
			NBTTagCompound nbttagcompound = new NBTTagCompound();

			if(this.equipment[i] != null) {
				this.equipment[i].writeToNBT(nbttagcompound);
			}

			nbttaglist0.appendTag(nbttagcompound);
		}

		tagCompound.setTag("Equipment", nbttaglist0);
//        tagCompound.setString("Species", this.getSpecies());
        tagCompound.setString("Char", this.getChar());
        tagCompound.setString("Cape", this.getCape());
        tagCompound.setBoolean("Willing", this.isWilling);
        tagCompound.setBoolean("Mating", this.isMating());
        tagCompound.setString("Align", this.alignment.name);
        tagCompound.setFloat("Height", this.getHeight());
        tagCompound.setInteger("Mana", this.getManaPoints());
        Enum type = this.getNpcClass();
        if(type != null)
        	tagCompound.setString("ClassType", this.species.classnames.inverse().get(type));

        NBTTagList nbttaglist = new NBTTagList();

        for (int i = 0; i < this.extraInventory.getSizeInventory(); ++i)
        {
            ItemStack itemstack = this.extraInventory.getStackInSlot(i);

            if (itemstack != null)
            {
                nbttaglist.appendTag(itemstack.writeToNBT(new NBTTagCompound()));
            }
        }

        tagCompound.setTag("Items", nbttaglist);
		if(this.trades != null)
			tagCompound.setTag("Offers", this.trades.getRecipiesAsTags());
        tagCompound.setInteger("healTimer", this.healTimer);
        if(this.skin != null)
        	tagCompound.setByteArray("Skin", this.skin);
	    
	    if(this.isPlayer()) {
	        for (int z = 0; z < this.inventory.mainInventory.length; z++)
	        {
	        	ItemStack itemstack = this.inventory.mainInventory[z];
	            if (itemstack != null)
	            {
	                this.getAttributeMap().applyAttributeModifiers(itemstack.getAttributeModifiers(2), z, itemstack.stackSize);
	            }
	        }
	        tagCompound.setTag("Inventory", this.inventory.writeToNBT(new NBTTagList()));
	        tagCompound.setInteger("SelectedItemSlot", this.inventory.currentItem);
	//        tagCompound.setBoolean("Sleeping", this.sleeping);
	//        tagCompound.setShort("SleepTimer", (short)this.sleepTimer);
	        tagCompound.setFloat("XpP", this.experience);
	        tagCompound.setInteger("XpLevel", this.experienceLevel);
	        tagCompound.setInteger("XpTotal", this.experienceTotal);
	        tagCompound.setInteger("XpSeed", this.xpSeed);
	//        tagCompound.setInteger("Score", this.getScore());
	//        tagCompound.setInteger("Mana", this.getManaPoints());
	
	        if (this.spawnPos != null)
	        {
	            tagCompound.setInteger("SpawnX", this.spawnPos.getX());
	            tagCompound.setInteger("SpawnY", this.spawnPos.getY());
	            tagCompound.setInteger("SpawnZ", this.spawnPos.getZ());
	            tagCompound.setInteger("SpawnDim", this.spawnPos.getDimension());
	//            tagCompound.setBoolean("SpawnForced", this.spawnForced);
	        }
	
	        if (this.originPos != null)
	        {
	            tagCompound.setInteger("OriginX", this.originPos.getX());
	            tagCompound.setInteger("OriginY", this.originPos.getY());
	            tagCompound.setInteger("OriginZ", this.originPos.getZ());
	            tagCompound.setInteger("OriginDim", this.originPos.getDimension());
	        }
	
	//        this.foodStats.writeNBT(tagCompound);
	//        this.writeCapabilitiesToNBT(tagCompound);
	        tagCompound.setBoolean("flying", this.flying);
	//        tagCompound.setFloat("speed", this.speed);
	//        tagCompound.setBoolean("alwaysInvulnerable", this.disableDamagePersist);
	//        tagCompound.setBoolean("neverTarget", this.disableTargetPersist);
	//        tagCompound.setBoolean("alwaysFly", this.allowFlyingPersist);
	        tagCompound.setBoolean("noClip", this.noclip);
	        
	        tagCompound.setTag("WarpItems", this.warpChest.saveInventoryToNBT());
	        ItemStack itemstack = this.inventory.getCurrentItem();
	
	        if (itemstack != null && itemstack.getItem() != null)
	        {
	            tagCompound.setTag("SelectedItem", itemstack.writeToNBT(new NBTTagCompound()));
	        }
	        
//	        tagCompound.setString("Model", this.getModel().name);
//	        tagCompound.setInteger("PartFlags", this.getModelParts());
	//        tagCompound.setFloat("PlayerScale", this.getPlayerHeight());
    	}
    }

    protected void damageArmor(int p_70675_1_)
    {
    	if(this.isPlayer())
    		this.inventory.damageArmor(p_70675_1_);
    }

    /**
     * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue
     */
    public int getTotalArmorValue()
    {
        return this.isPlayer() ? this.inventory.getTotalArmorValue() : super.getTotalArmorValue();
    }

    public boolean interactWith(Entity targetEntity)
    {
//        if (this.isSpectator())
//        {
//            if (targetEntity instanceof IInventory)
//            {
//                this.displayGUIChest((IInventory)targetEntity);
//            }
//
//            return false;
//        }
//        else
//        {
            ItemStack itemstack = this.getCurrentEquippedItem();
            ItemStack itemstack1 = itemstack != null ? itemstack.copy() : null;

            if (!targetEntity.interactFirst(this))
            {
                if (itemstack != null && targetEntity instanceof EntityLiving)
                {
//                    if (this.creative)
//                    {
//                        itemstack = itemstack1;
//                    }

                    if (itemstack.interactWithEntity(this, (EntityLiving)targetEntity))
                    {
                        if (itemstack.stackSize <= 0) // && !this.creative)
                        {
                            this.destroyCurrentEquippedItem();
                        }

                        return true;
                    }
                }

                return false;
            }
            else
            {
                if (itemstack != null && itemstack == this.getCurrentEquippedItem())
                {
                    if (itemstack.stackSize <= 0) // && !this.creative)
                    {
                        this.destroyCurrentEquippedItem();
                    }
//                    else if (itemstack.stackSize < itemstack1.stackSize && this.creative)
//                    {
//                        itemstack.stackSize = itemstack1.stackSize;
//                    }
                }

                return true;
            }
//        }
    }

    /**
     * Returns the currently being used item by the player.
     */
    public ItemStack getCurrentEquippedItem()
    {
        return this.inventory.getCurrentItem();
    }

    /**
     * Destroys the currently equipped item from the player's inventory.
     */
    public void destroyCurrentEquippedItem()
    {
        this.inventory.setInventorySlotContents(this.inventory.currentItem, (ItemStack)null);
    }

    /**
     * Returns the Y Offset of this entity.
     */
    public double getYOffset()
    {
        return this.isPlayer() ? -0.35D : super.getYOffset();
    }

    /**
     * Attacks for the player the targeted entity with the currently equipped item.  The equipped item has hitEntity
     * called on it. Args: targetEntity
     */
    public void attackTargetEntityWithCurrentItem(Entity targetEntity)
    {
    	if(!this.worldObj.client) {
	    	if(/* !this.creative && */ this.sinceLastAttack < Config.attackDelay)
	    		return;
	    	this.sinceLastAttack = 0;
    	}
        if (targetEntity.canAttackWithItem())
        {
            if (!targetEntity.hitByEntity(this))
            {
                int f = (int)this.getEntityAttribute(Attributes.ATTACK_DAMAGE).getAttributeValue();
                int i = 0;
                int f1 = // 0;

//                if (targetEntity instanceof EntityLivingBase)
//                {
//                    f1 = EnchantmentHelper.getModifierForCreature(this.getHeldItem());
//                }
//                else
//                {
//                    f1 = 
                    EnchantmentHelper.getDamageModifier(this.getHeldItem());
//                }

                i = i + EnchantmentHelper.getKnockbackModifier(this);

                if (this.isSprinting())
                {
                    ++i;
                }

                if (f > 0 || f1 > 0)
                {
                    boolean flag = this.fallDistance > 0.0F && !this.onGround && !this.isOnLadder() && !this.isInLiquid() && !this.hasEffect(Potion.BLINDNESS) && this.vehicle == null && targetEntity instanceof EntityLiving;

                    if (flag && f > 0)
                    {
                        f = (int)((float)f * 1.5F);
                    }

                    f = f + f1;
                    boolean flag1 = false;
                    int j = EnchantmentHelper.getFireAspectModifier(this);

                    if (targetEntity instanceof EntityLiving && j > 0 && !targetEntity.isBurning())
                    {
                        flag1 = true;
                        targetEntity.setFire(1);
                    }

                    double d0 = targetEntity.motionX;
                    double d1 = targetEntity.motionY;
                    double d2 = targetEntity.motionZ;
                    boolean flag2 = (this.worldObj.client || Config.attack) && targetEntity.attackEntityFrom(DamageSource.causeMobDamage(this), f);

                    if (flag2)
                    {
                        if (i > 0)
                        {
                            targetEntity.addKnockback((double)(-ExtMath.sin(this.rotYaw * (float)Math.PI / 180.0F) * (float)i * 0.5F), 0.1D, (double)(ExtMath.cos(this.rotYaw * (float)Math.PI / 180.0F) * (float)i * 0.5F));
                            this.motionX *= 0.6D;
                            this.motionZ *= 0.6D;
                            this.setSprinting(false);
                        }

                        if (!this.worldObj.client && targetEntity.isPlayer() && targetEntity.veloChanged)
                        {
                            ((EntityNPC)targetEntity).connection.sendPacket(new SPacketEntityVelocity(targetEntity));
                            targetEntity.veloChanged = false;
                            targetEntity.motionX = d0;
                            targetEntity.motionY = d1;
                            targetEntity.motionZ = d2;
                        }

                        if (flag)
                        {
                            this.onCriticalHit(targetEntity);
                        }

                        if (f1 > 0.0F)
                        {
                            this.onEnchantmentCritical(targetEntity);
                        }

                        this.setLastAttack(targetEntity);

                        if (targetEntity instanceof EntityLiving)
                        {
                            EnchantmentHelper.applyThornEnchantments((EntityLiving)targetEntity, this);
                        }

                        EnchantmentHelper.applyArthropodEnchantments(this, targetEntity);
                        ItemStack itemstack = this.getCurrentEquippedItem();
                        Entity entity = targetEntity;

                        if (targetEntity instanceof EntityDragonPart)
                        {
                            IEntityMultiPart ientitymultipart = ((EntityDragonPart)targetEntity).entityDragonObj;

                            if (ientitymultipart instanceof EntityLiving)
                            {
                                entity = (EntityLiving)ientitymultipart;
                            }
                        }

                        if (itemstack != null && entity instanceof EntityLiving)
                        {
                            itemstack.hitEntity((EntityLiving)entity, this);

                            if (itemstack.stackSize <= 0)
                            {
                                this.destroyCurrentEquippedItem();
                            }
                        }

                        if (targetEntity instanceof EntityLiving)
                        {
//                            this.addStat(StatRegistry.damageDealtStat, f);

                            if (j > 0)
                            {
                                targetEntity.setFire(j * 4);
                            }
                        }
                    }
                    else if (flag1)
                    {
                        targetEntity.extinguish();
                    }
                }
            }
        }
    }

    /**
     * Will get destroyed next tick.
     */
    public void setDead()
    {
        super.setDead();
        if(this.isPlayer()) {
	        this.inventoryContainer.onContainerClosed(this);
	
	        if (this.openContainer != null)
	        {
	            this.openContainer.onContainerClosed(this);
	        }
        }
    }

    /**
     * Return null if bed is invalid
     */
    public static BlockPos getBedSpawnLocation(World worldIn, BlockPos bedLocation)
    {
        Block block = worldIn.getState(bedLocation).getBlock();

        if (!(block instanceof BlockBed))
        {
            return null;
        }
        else
        {
            return BlockBed.getSafeExitLocation(worldIn, bedLocation, 0);
        }
    }

    public WorldPos getSpawnPoint()
    {
        return this.spawnPos;
    }

    public void setSpawnPoint(WorldPos pos)
    {
        this.spawnPos = pos;
    }

    public WorldPos getOrigin()
    {
        return this.originPos;
    }

    public void setOrigin(WorldPos pos)
    {
        this.originPos = pos;
    }

//    /**
//     * Will trigger the specified trigger.
//     */
//    public void triggerAchievement(StatBase achievementIn)
//    {
//        this.addStat(1);
//    }

//    /**
//     * Causes this entity to do an upwards motion (jumping).
//     */
//    public void jump()
//    {
//        super.jump();
//        if(this.isPlayer())
//        	this.triggerAchievement(StatRegistry.jumpStat);
//    }

    /**
     * Moves the entity based on the specified heading.  Args: strafe, forward
     */
    public void moveEntityWithHeading(float strafe, float forward)
    {
    	if(!this.isPlayer()) {
    		super.moveEntityWithHeading(strafe, forward);
    		return;
    	}
        double d0 = this.posX;
        double d1 = this.posY;
        double d2 = this.posZ;

        if (this.isFlying() && this.vehicle == null)
        {
            double d3 = this.motionY;
            float f = this.jumpMovement;
            this.jumpMovement = this.landMovement * (this.canFlyFullSpeed() ? 0.5f : 0.2f) * (float)(this.isSprinting() ? 2 : 1);
            super.moveEntityWithHeading(strafe, forward);
            this.motionY = d3 * 0.6D;
            this.jumpMovement = f;
        }
        else
        {
            super.moveEntityWithHeading(strafe, forward);
        }

        this.addMovementStat(this.posX - d0, this.posY - d1, this.posZ - d2);
    }

    /**
     * the movespeed used for the new AI system
     */
    public float getAIMoveSpeed()
    {
        return this.isPlayer() ? (float)this.getEntityAttribute(Attributes.MOVEMENT_SPEED).getAttributeValue() : super.getAIMoveSpeed();
    }

    /**
     * Adds a value to a movement statistic field - like run, walk, swin or climb.
     */
    public void addMovementStat(double p_71000_1_, double p_71000_3_, double p_71000_5_)
    {
        if (this.vehicle == null)
        {
            if (this.isInsideOfLiquid())
            {
                int i = Math.round(ExtMath.sqrtd(p_71000_1_ * p_71000_1_ + p_71000_3_ * p_71000_3_ + p_71000_5_ * p_71000_5_) * 100.0F);

                if (i > 0)
                {
                    this.addStat(i);
                }
            }
            else if (this.isInLiquid())
            {
                int j = Math.round(ExtMath.sqrtd(p_71000_1_ * p_71000_1_ + p_71000_5_ * p_71000_5_) * 100.0F);

                if (j > 0)
                {
                    this.addStat(j);
                }
            }
            else if (this.isOnLadder())
            {
                if (p_71000_3_ > 0.0D)
                {
                    this.addStat((int)Math.round(p_71000_3_ * 100.0D));
                }
            }
            else if (this.onGround)
            {
                int k = Math.round(ExtMath.sqrtd(p_71000_1_ * p_71000_1_ + p_71000_5_ * p_71000_5_) * 100.0F);

                if (k > 0)
                {
                    this.addStat(k);

//                    if (this.isSprinting())
//                    {
//                        this.addStat(StatRegistry.distanceSprintedStat, k);
//                    }
//                    else
//                    {
//                        if (this.isSneaking())
//                        {
//                            this.addStat(StatRegistry.distanceCrouchedStat, k);
//                        }
//                    }
                }
            }
            else
            {
                int l = Math.round(ExtMath.sqrtd(p_71000_1_ * p_71000_1_ + p_71000_5_ * p_71000_5_) * 100.0F);

                if (l > 25)
                {
                    this.addStat(l);
                }
            }
        }
    }

    /**
     * Adds a value to a mounted movement statistic field - by minecart, boat, or pig.
     */
    private void addMountedMovementStat(double p_71015_1_, double p_71015_3_, double p_71015_5_)
    {
        if (this.vehicle != null)
        {
            int i = Math.round(ExtMath.sqrtd(p_71015_1_ * p_71015_1_ + p_71015_3_ * p_71015_3_ + p_71015_5_ * p_71015_5_) * 100.0F);

            if (i > 0)
            {
                if (this.vehicle instanceof EntityCart)
                {
                    this.addStat(i);

//                    if (this.startMinecartRidingCoordinate == null)
//                    {
//                        this.startMinecartRidingCoordinate = new BlockPos(this);
//                    }
                }
                else if (this.vehicle instanceof EntityBoat)
                {
                    this.addStat(i);
                }
                else if (this.vehicle instanceof EntityPig)
                {
                    this.addStat(i);
                }
                else if (this.vehicle instanceof EntityHorse)
                {
                    this.addStat(i);
                }
            }
        }
    }

    public void fall(float distance, float damageMultiplier)
    {
    	if(!this.isPlayer()) {
    		super.fall(distance, damageMultiplier);
    		return;
    	}
        if (!this.noclip && this.worldObj.gravity != 0.0)
        {
            if (distance >= 2.0F)
            {
                this.addStat((int)Math.round((double)distance * 100.0D));
            }

            if(!this.hasEffect(Potion.FLYING))
            	super.fall(distance, damageMultiplier);
        }
    }

    public void makeLandingParticles(BlockPos pos)
    {
        if (!this.isPlayer() || (!this.noclip && this.worldObj.gravity != 0.0))
        {
    		super.makeLandingParticles(pos);
        }
    }
    
    protected void onEnterLiquid()
    {
        if (!this.isPlayer() || !this.noclip)
        {
            super.onEnterLiquid();
        }
    }

//    /**
//     * This method gets called when the entity kills another one.
//     */
//    public void onKillEntity(EntityLiving entityLivingIn)
//    {
//    	if(this.isPlayer()) {
//	        EntityEggInfo entitylist$entityegginfo = (EntityEggInfo)EntityRegistry.SPAWN_EGGS.get(EntityRegistry.getEntityString(entityLivingIn));
//	
//	        if (entitylist$entityegginfo != null)
//	        {
//	            this.triggerAchievement(entitylist$entityegginfo.killStat);
//	        }
//    	}
//    }

    /**
     * Sets the Entity inside a web block.
     */
    public void setInWeb()
    {
        if (!this.isPlayer() || !this.flying)
        {
            super.setInWeb();
        }
    }

    public ItemStack getArmor(int slot)
    {
        return this.isPlayer() ? this.inventory.armorItemInSlot(slot) : this.equipment[slot + 1];
    }

    /**
     * Add experience points to player.
     */
    public void addExperience(int amount)
    {
        int i = Integer.MAX_VALUE - this.experienceTotal;

        if (amount > i)
        {
            amount = i;
        }

        this.experience += (float)amount / (float)this.xpBarCap();

        for (this.experienceTotal += amount; this.experience >= 1.0F; this.experience /= (float)this.xpBarCap())
        {
            this.experience = (this.experience - 1.0F) * (float)this.xpBarCap();
            this.addExperienceLevel(1);
        }
    }

    public int getXPSeed()
    {
        return this.xpSeed;
    }

    public void setXPSeed(int xpSeed)
    {
        this.xpSeed = xpSeed;
    }

    /**
     * This method returns the cap amount of experience that the experience bar can hold. With each level, the
     * experience cap on the player's experience bar is raised by 10.
     */
    public int xpBarCap()
    {
        return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2);
    }

    /**
     * sets the itemInUse when the use item button is clicked. Args: itemstack, int maxItemUseDuration
     */
    public void setItemInUse(ItemStack stack, int duration)
    {
        if (stack != this.itemInUse)
        {
            this.itemInUse = stack;
            this.itemInUseCount = duration;

            if (!this.worldObj.client)
            {
                this.setUsingItem(true);
            }
        }
    }

    public boolean canPlayerEdit(BlockPos pos, Facing side, ItemStack stack)
    {
        return true;
    }

    /**
     * Get the experience points the entity currently has.
     */
    protected int getExperiencePoints(EntityNPC player)
    {
        return this.isPlayer() ? 0 : this.worldObj.rand.range(2, 5);
    }

    /**
     * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
     * prevent them from trampling crops
     */
    protected boolean canTriggerWalking()
    {
        return !this.isPlayer() || !this.flying;
    }

    /**
     * Returns the InventoryWarpChest of this player.
     */
    public InventoryWarpChest getWarpChest()
    {
        return this.warpChest;
    }
    
    public void setWarpChest(InventoryWarpChest warpChest)
    {
        this.warpChest = warpChest;
    }

    /**
     * 0: Tool in Hand; 1-4: Armor
     */
    public ItemStack getItem(int slot)
    {
        return this.isPlayer() ? (slot == 0 ? this.inventory.getCurrentItem() : this.inventory.armorInventory[slot - 1]) : this.equipment[slot];
    }

    /**
     * Returns the item that this EntityLiving is holding, if any.
     */
    public ItemStack getHeldItem()
    {
        return this.isPlayer() ? this.inventory.getCurrentItem() : this.equipment[0];
    }

    
    /**
     * returns the inventory of this entity (only used in EntityNPCMP it seems)
     */
    public ItemStack[] getInventory()
    {
        return this.isPlayer() ? this.inventory.armorInventory : this.equipment;
    }

    public boolean isPushedByWater()
    {
        return !this.isPlayer() || !this.flying;
    }
    
    public String getName()
    {
//    	if(this.isPlayer())
//    		return this.getAlignment().color + (this.hasCustomName() ? this.getCustomNameTag() : "<?>");
        String text = this.getPrefix();
//        Enum cls = this.getNpcClass();
        if(text == null || text.isEmpty()) {
        	text = this.getTypeName();
        }
        else {
//        	text = new TextComponent("entity.className." + cls.name().toLowerCase());
        	if(this.hasCustomName())
        		text += " " + this.getCustomNameTag();
        }
        return this.getAlignment().color + text;
//        this.formatComponent(comp);
//        text.setColor();
//        return comp;
    }

    public float getEyeHeight()
    {
    	if(!this.isPlayer())
            return 1.62F * this.height / 1.8f;
        float f = 1.62F * this.height / 1.8f; // this.getHeight(); // / 1.8f;

        if (this.isSneakingVisually())
        {
            f -= 0.08F * this.height / 1.8f; // this.getHeight(); // / 1.8f;
        }

        return f;
    }

    public void setAbsorptionAmount(int amount)
    {
    	if(!this.isPlayer()) {
    		super.setAbsorptionAmount(amount);
    	}
    	else {
	        if (amount < 0)
	        {
	            amount = 0;
	        }
	
	        this.getDataWatcher().updateObject(30, Integer.valueOf(amount));
    	}
    }

    public int getAbsorptionAmount()
    {
        return this.isPlayer() ? this.getDataWatcher().getWatchableObjectInt(30) : super.getAbsorptionAmount();
    }
    
    public boolean canOpen(LockCode code)
    {
        if (code.isEmpty())
            return true;
        ItemStack stack = this.getCurrentEquippedItem();
        return stack != null && stack.getItem() == Items.key && 
        		stack.hasDisplayName() && stack.getDisplayName().equals(code.getLock());
    }

//    public boolean isWearing(ModelPart part)
//    {
//        return this.isPlayer() ? (this.getDataWatcher().getWatchableObjectInt(10) & part.getMask()) == part.getMask()
//        		: (part != ModelPart.ARMS_SLIM || this.hasSlimSkin());
//    }
//
//    public int getModelParts()
//    {
//        return this.getDataWatcher().getWatchableObjectInt(10);
//    }
//
//    public void setModelParts(int parts)
//    {
//        this.getDataWatcher().updateObject(10, Integer.valueOf(parts));
//    }
    
    public int getTrackingRange() {
    	return this.isPlayer() ? 512 : 80;
    }
    
    public int getUpdateFrequency() {
    	return this.isPlayer() ? 2 : 3;
    }
    
    public boolean isSendingVeloUpdates() {
    	return !this.isPlayer();
    }
    
    public boolean isFlying() {
    	return this.flying || this.worldObj.gravity == 0.0;
    }
    
    public boolean canNaturallyFly() {
    	return false;
    }
    
    public boolean canFlyFullSpeed() {
    	return this.flying;
    }

	public int getEnergy(Energy type) { // TODO
		return 0;
	}

	public boolean hasEnergyEffect(Energy type) {
		return false;
	}

	public boolean isEnergyDrawn(Energy type) {
		return false;
	}
	
	// livingbase override

    protected void dropFewItems(boolean wasRecentlyHit, int lootingModifier)
    {
    	if(!this.isPlayer()) {
    		super.dropFewItems(wasRecentlyHit, lootingModifier);
            this.dropEquipment();
    	}
    }

	public Object onInitialSpawn(Object livingdata) {
//		if(this.isPlayer()) {
//			this.setCustomNameTag(this.pickRandomName(this.rand, null));
//			return livingdata;
//		}
        livingdata = super.onInitialSpawn(livingdata);
        CharacterInfo info = (livingdata instanceof CharacterTypeData) ? ((CharacterTypeData)livingdata).character : 
        		this.species.pickCharacter(this.worldObj.rand);
        AlignmentData align = livingdata instanceof AlignmentData ? ((AlignmentData)livingdata) : null;
    	this.setStats(info);
    	if(align != null)
    		this.setAlignment(align.alignment);
    	return align != null ? align : new AlignmentData(this.alignment);
	}

	public void setStats(NpcInfo info) {
    	this.setNpcClass(info.type == null ? this.pickRandomClass() : info.type);
    	this.setChar(info.skin != null ? info.skin : this.pickRandomTexture());
    	this.setCape(info.cape != null ? info.cape : this.pickRandomAccessory());
    	this.setCustomNameTag(info.name.isEmpty() ? this.pickRandomName() : info.name);
    	this.setAlignment(info.align != null ? info.align : this.getNaturalAlign());
    	this.setHeight(info.height > 0.0f ? info.height : this.getBaseSize());
    	if(!this.isPlayer()) {
    		if(info.items != null) {
	    		for(ItemStack stack : info.items) {
	    			if(stack.getItem() instanceof ItemArmor)
	    				this.setItem(1 + ((ItemArmor)stack.getItem()).armorType, stack);
	    			else if(stack.getItem().canBeWielded())
	    				this.setItem(0, stack);
	    			else
	    				this.extraInventory.addStack(stack);
	    		}
    		}
    		else {
    			this.setItem(0, this.pickItem());
    	    	for(int z = 0; z < 4; z++) {
    	    		this.setItem(z + 1, this.pickArmor(z));
    	    	}
    	    	int items = this.pickItemAmount();
    	    	ItemStack stack;
    	    	this.extraInventory.clear();
    	    	for(int z = 0; z < items; z++) {
    	    		stack = this.pickLoot(z);
    	    		if(stack == null) {
    	    			break;
    	    		}
    	    		this.extraInventory.addStack(stack);
    	    	}
    		}
    	}
	}
	
	public String pickRandomTexture() {
		return "";
	}
	
	public String pickRandomAccessory() {
		return "";
	}
	
	public Enum pickRandomClass() {
		return null;
	}
	
    public boolean interactFirst(EntityNPC playerIn)
    {
        return !this.isPlayer() && super.interactFirst(playerIn);
    }
    
    public int getMaxFallHeight()
    {
        return this.isPlayer() ? 3 : super.getMaxFallHeight();
    }
    
	protected void updateLeashedState() {
		if(!this.isPlayer())
			super.updateLeashedState();
	}

	public void setLeashedTo(Entity entity, boolean pkt) {
		if(!this.isPlayer())
			super.setLeashedTo(entity, pkt);
	}

	public boolean allowLeashing() {
		return !this.isPlayer();
	}
	
	public void clearLeashed(boolean pkt, boolean dropLead) {
		if(!this.isPlayer())
			super.clearLeashed(pkt, dropLead);
	}

    protected float updateDistance(float p_110146_1_, float p_110146_2_)
    {
		if(!this.isPlayer())
			return super.updateDistance(p_110146_1_, p_110146_2_);
        float f = ExtMath.wrapf(p_110146_1_ - this.yawOffset);
        this.yawOffset += f * 0.3F;
        float f1 = ExtMath.wrapf(this.rotYaw - this.yawOffset);
        boolean flag = f1 < -90.0F || f1 >= 90.0F;

        if (f1 < -75.0F)
        {
            f1 = -75.0F;
        }

        if (f1 >= 75.0F)
        {
            f1 = 75.0F;
        }

        this.yawOffset = this.rotYaw - f1;

        if (f1 * f1 > 2500.0F)
        {
            this.yawOffset += f1 * 0.2F;
        }

        if (flag)
        {
            p_110146_2_ *= -1.0F;
        }

        return p_110146_2_;
    }

	public boolean getCanSpawnHere() {
		return this.isPlayer() || super.getCanSpawnHere();
	}
	
	// npc overrides

    
    public void setScaleForAge() {
    	if(!this.isPlayer())
	        this.setScale((float)((int)(100.0f * (this.getHeight() / this.getSpeciesBaseSize()) * (this.getGrowingAge() < 0 ? 1.0f + 
	        		((float)Math.max(-24000, this.getGrowingAge()) / 24000.0f) * 0.6f : 1.0f))) / 100.0f);
    }
    
    protected void dropEquipment()
    {
    	if(this.isPlayer())
    		return;
    	for (int i = 0; i < this.getInventory().length; ++i)
        {
            ItemStack itemstack = this.getItem(i);
            if (itemstack != null)
            {
                this.entityDropItem(itemstack, 0.0F);
            }
        }
        for (int i = 0; i < this.extraInventory.getSizeInventory(); ++i)
        {
            ItemStack itemstack = this.extraInventory.getStackInSlot(i);
            if (itemstack != null)
            {
                this.entityDropItem(itemstack, 0.0F);
            }
        }
    }
    
    public EntityNPC createChild(EntityLiving ageable)
    {
//    	if(this.isPlayer())
//    		return null;
        EntityNPC template = (ageable instanceof EntityNPC && this.worldObj.rand.chance() ? ((EntityNPC)ageable) : this);
        EntityNPC entity;
		try {
			entity = template.getClass().getConstructor(World.class).newInstance(this.worldObj);
		}
		catch(InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException e) {
			throw new RuntimeException(e);
		}
        entity.onInitialSpawn(new CharacterTypeData(
        		template.species.pickCharacter(this.worldObj.rand)));
//        EntityNPC base = ;
//        entity.setSpecies(base.getSpecies());
//        entity.setChar(base.getChar());
//        entity.setCape(base.getCape());
//        entity.setCustomNameTag(base.getCustomNameTag());
//        for(int z = 0; z < 5; z++) {
//        	entity.setCurrentItemOrArmor(z, base.getEquipmentInSlot(z) == null ? null : base.getEquipmentInSlot(z).copy());
//    	}
//        entity.extraInventory.clear();
        return entity;
    }
    
    public void setItemNoUpdate(int slot, ItemStack stack)
    {
    	if(!this.isPlayer())
    		this.equipment[slot] = stack;
    }
    
    public void setCombatTask()
    {
    	if(!this.isPlayer()) {
            this.tasks.removeTask(this.aiMelee);
            this.tasks.removeTask(this.aiRanged);
            ItemStack itemstack = this.getHeldItem();

            if (this.isRangedWeapon(itemstack))
            {
                this.tasks.addTask(3, this.aiRanged);
            }
            else
            {
                this.tasks.addTask(3, this.aiMelee);
            }
    	}
    }

	public abstract int getBaseHealth(Random rand); // {
//		return 20;
//	}

	public abstract Alignment getNaturalAlign(); // {
//		return Alignment.NEUTRAL;
//	}

	public boolean canPlay() {
		return !this.isPlayer() && this.getGrowingAge() <= -14000;
	}
    
    public final float getBaseSize() {
    	return this.getEntityBaseSize() + this.getHeightDeviation(this.rand);
    }
    
    public int getCurrentSize() {
    	return (int)(this.getHeight() * 100.0f + 0.5f);
    }
    
    public int getDefaultSize() {
    	return (int)(this.getEntityBaseSize() * 100.0f + 0.5f);
    }
    
    public int getMinSize() {
    	return (int)((this.getEntityBaseSize() + this.getHeightDeviationMin()) * 100.0f + 0.5f);
    }
    
    public int getMaxSize() {
    	return (int)((this.getEntityBaseSize() + this.getHeightDeviationMax()) * 100.0f + 0.5f);
    }
    
    public ModelType getModel() {
    	return this.species.renderer;
//    	return ModelType.values()[this.dataWatcher.getWatchableObjectByte(11) % ModelType.values().length];
    }
//    
//    public void setModel(ModelType model) {
//    	this.dataWatcher.updateObject(11, (byte)model.ordinal());
//    }

	public int getColor() {
        return this.isPlayer() ? 0xff00ff : 0x5000ad;
	}
	
    public void sendDeathMessage() {
		this.sendDeathMessage(this.isPlayer(), true);
	}
    
	protected boolean canRegenerateHealth() {
		return this.isPlayer();
	}
	
	// END PLAYER
	
    public Item getItem() {
        for(int z = 0; z < this.species.chars.length; z++) {
        	if(this.species.chars[z].spawner && this.species.chars[z].skin.equals(this.getChar())) {
                return ItemRegistry.getRegisteredItem(this.species.chars[z].skin + "_spawner");
        	}
        }
        return super.getItem();
    }
    
    public boolean isHovering()
    {
        return false;
    }

    public void setHovering(boolean hover)
    {
    }
    
    public EntityType getType() {
    	return EntityType.NPC;
    }
}
