content: package thebetweenlands.common.entity;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import javax.annotation.Nullable;
  
  import net.minecraft.entity.Entity;
  import net.minecraft.entity.EntityLivingBase;
  import net.minecraft.entity.IEntityMultiPart;
  import net.minecraft.entity.MoverType;
  import net.minecraft.entity.MultiPartEntityPart;
  import net.minecraft.nbt.NBTTagCompound;
  import net.minecraft.network.datasync.DataParameter;
  import net.minecraft.network.datasync.DataSerializers;
  import net.minecraft.network.datasync.EntityDataManager;
  import net.minecraft.util.DamageSource;
  import net.minecraft.util.EntityDamageSource;
  import net.minecraft.util.EntityDamageSourceIndirect;
  import net.minecraft.util.SoundCategory;
  import net.minecraft.util.math.AxisAlignedBB;
  import net.minecraft.util.math.BlockPos;
  import net.minecraft.util.math.MathHelper;
  import net.minecraft.util.math.Vec3d;
  import net.minecraft.world.World;
  import net.minecraftforge.fml.relauncher.Side;
  import net.minecraftforge.fml.relauncher.SideOnly;
  import thebetweenlands.common.entity.mobs.EntityFortressBoss;
  import thebetweenlands.common.entity.mobs.EntitySludgeMenace.DummyPart;
  import thebetweenlands.common.registries.SoundRegistry;
  import thebetweenlands.common.tile.TileEntityDecayPitControl;
  import thebetweenlands.common.tile.TileEntityDecayPitGroundChain;
  import thebetweenlands.common.tile.TileEntityDecayPitHangingChain;
  import thebetweenlands.util.RotationMatrix;
  
  public class EntityDecayPitTarget extends Entity implements IEntityMultiPart {
  	private static final byte EVENT_ATTACK_BLOCKED = 80;
  	private static final byte EVENT_ATTACK_DAMAGE = 81;
  
  	private final RotationMatrix rotationMatrix = new RotationMatrix();
  
  	public float animationTicksPrev = 0;
  	public int animationTicksChain = 0;
  	public int animationTicksChainPrev = 0;
  	public final int MAX_PROGRESS = 768; // max distance of travel from origin so; 768 * 0.0078125F = 6 Blocks
  	public final int MIN_PROGRESS = 0;
  	public final float MOVE_UNIT = 0.0078125F; // unit of movement 
  	public EntityDecayPitTargetPart[] parts;
  	public EntityDecayPitTargetPart shield_1;
  	public EntityDecayPitTargetPart shield_2;
  	public EntityDecayPitTargetPart shield_3;
  	public EntityDecayPitTargetPart shield_4;
  	public EntityDecayPitTargetPart shield_5;
  	public EntityDecayPitTargetPart shield_6;
  	public EntityDecayPitTargetPart shield_7;
  	public EntityDecayPitTargetPart shield_8;
  	public EntityDecayPitTargetPart shield_9;
  	public EntityDecayPitTargetPart shield_10;
  	public EntityDecayPitTargetPart shield_11;
  	public EntityDecayPitTargetPart shield_12;
  	public EntityDecayPitTargetPart shield_13;
  	public EntityDecayPitTargetPart shield_14;
  	public EntityDecayPitTargetPart shield_15;
  	public EntityDecayPitTargetPart shield_16;
  	public EntityDecayPitTargetPart target_north;
  	public EntityDecayPitTargetPart target_east;
  	public EntityDecayPitTargetPart target_west;
  	public EntityDecayPitTargetPart target_south;
  	public EntityDecayPitTargetPart bottom;
  
  	private static final DataParameter<Float> ANIMATION_TICKS = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.FLOAT);
  	private static final DataParameter<Boolean> IS_RAISING = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.BOOLEAN);
  	private static final DataParameter<Boolean> IS_MOVING = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.BOOLEAN);
  	private static final DataParameter<Boolean> IS_SLOW = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.BOOLEAN);
  	private static final DataParameter<Integer> PROGRESS = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.VARINT);
  	private static final DataParameter<Boolean> TARGET_N_ACTIVE = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.BOOLEAN);
  	private static final DataParameter<Boolean> TARGET_E_ACTIVE = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.BOOLEAN);
  	private static final DataParameter<Boolean> TARGET_S_ACTIVE = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.BOOLEAN);
  	private static final DataParameter<Boolean> TARGET_W_ACTIVE = EntityDataManager.createKey(EntityDecayPitTarget.class, DataSerializers.BOOLEAN);
  
  	public int attackDamageTicks = 0;
  	public int[] beamTransparencyTicks = new int[4];
  
  	public int renderedFrame = -1;
  	public int renderedFrameMultipass = -1;
  	
  	private DummyPart[] dummies;
  	
  	public EntityDecayPitTarget(World world) {
  		super(world);
  		setSize(5F, 5F);
  		parts = new EntityDecayPitTargetPart[] {
  				shield_1 = new EntityDecayPitTargetPart(this, "part1", 1F, 1F, true),
  				shield_2 = new EntityDecayPitTargetPart(this, "part2", 1F, 1F, true),
  				shield_3 = new EntityDecayPitTargetPart(this, "part3", 1F, 1F, true),
  				shield_4 = new EntityDecayPitTargetPart(this, "part4", 1F, 1F, true),
  				shield_5 = new EntityDecayPitTargetPart(this, "part5", 1F, 1F, true),
  				shield_6 = new EntityDecayPitTargetPart(this, "part6", 1F, 1F, true),
  				shield_7 = new EntityDecayPitTargetPart(this, "part7", 1F, 1F, true),
  				shield_8 = new EntityDecayPitTargetPart(this, "part8", 1F, 1F, true),
  				shield_9 = new EntityDecayPitTargetPart(this, "part9", 1F, 1F, true),
  				shield_10 = new EntityDecayPitTargetPart(this, "part10", 1F, 1F, true),
  				shield_11 = new EntityDecayPitTargetPart(this, "part11", 1F, 1F, true),
  				shield_12 = new EntityDecayPitTargetPart(this, "part12", 1F, 1F, true),
  				shield_13 = new EntityDecayPitTargetPart(this, "part13", 1F, 1F, true),
  				shield_14 = new EntityDecayPitTargetPart(this, "part16", 1F, 1F, true),
  				shield_15 = new EntityDecayPitTargetPart(this, "part15", 1F, 1F, true),
  				shield_16 = new EntityDecayPitTargetPart(this, "part16", 1F, 1F, true),
  				target_north = new EntityDecayPitTargetPart(this, "target_north", 2F, 2F, false),
  				target_east = new EntityDecayPitTargetPart(this, "target_east", 2F, 2F, false),
  				target_south = new EntityDecayPitTargetPart(this, "target_south", 2F, 2F, false),
  				target_west = new EntityDecayPitTargetPart(this, "target_west", 2F, 2F, false),
  				bottom = new EntityDecayPitTargetPart(this, "bottom", 3F, 1F, false),
  				};
  		this.dummies = new DummyPart[parts.length];
  	}
  
  	@Override
  	protected void entityInit() {
  		dataManager.register(IS_RAISING, false);
  		dataManager.register(IS_MOVING, false);
  		dataManager.register(IS_SLOW, true);
  		dataManager.register(PROGRESS, 0);
  		dataManager.register(ANIMATION_TICKS, 0.0F);
  		dataManager.register(TARGET_N_ACTIVE, true);
  		dataManager.register(TARGET_E_ACTIVE, true);
  		dataManager.register(TARGET_W_ACTIVE, true);
  		dataManager.register(TARGET_S_ACTIVE, true);
  	}
  
  	@Override
  	public void onUpdate() {
  		super.onUpdate();
  		
  		if(this.attackDamageTicks > 0) {
  			this.attackDamageTicks--;
  		}
  
  		boolean isMovingDown = this.isMoving() && !this.isSlow();
  
  		if(this.getTargetEActive() && !isMovingDown) {
  			this.beamTransparencyTicks[0] = Math.min(15, this.beamTransparencyTicks[0] + 1);
  		} else {
  			this.beamTransparencyTicks[0] = Math.max(0, this.beamTransparencyTicks[0] - 1);
  		}
  
  		if(this.getTargetWActive() && !isMovingDown) {
  			this.beamTransparencyTicks[1] = Math.min(15, this.beamTransparencyTicks[1] + 1);
  		} else {
  			this.beamTransparencyTicks[1] = Math.max(0, this.beamTransparencyTicks[1] - 1);
  		}
  
  		if(this.getTargetSActive() && !isMovingDown) {
  			this.beamTransparencyTicks[2] = Math.min(15, this.beamTransparencyTicks[2] + 1);
  		} else {
  			this.beamTransparencyTicks[2] = Math.max(0, this.beamTransparencyTicks[2] - 1);
  		}
  
  		if(this.getTargetNActive() && !isMovingDown) {
  			this.beamTransparencyTicks[3] = Math.min(15, this.beamTransparencyTicks[3] + 1);
  		} else {
  			this.beamTransparencyTicks[3] = Math.max(0, this.beamTransparencyTicks[3] - 1);
  		}
  
  		float animationTicks = this.dataManager.get(ANIMATION_TICKS);
  
  		animationTicksPrev = animationTicks;
  		animationTicksChainPrev = animationTicksChain;
  
  		if(!this.world.isRemote) {
  			if (animationTicks + 1 >= 360F) {
  				this.dataManager.set(ANIMATION_TICKS, 0.0F);
  			} else {
  				this.dataManager.set(ANIMATION_TICKS, animationTicks + 1);
  			}
  		}
  
  		while(animationTicks - this.animationTicksPrev < -180.0F) {
  			this.animationTicksPrev -= 360.0F;
          }
          while(animationTicks - this.animationTicksPrev >= 180.0F) {
          	this.animationTicksPrev += 360.0F;
          }
  
          //Set prev pos, rotation, etc.
          for(Entity entity : parts) {
          	entity.onUpdate();
          }
  
  		setNewShieldHitboxPos(animationTicks, shield_1);
  		setNewShieldHitboxPos(-animationTicks + 22.5F, shield_2);
  		setNewShieldHitboxPos(animationTicks + 45F, shield_3);
  		setNewShieldHitboxPos(-animationTicks + 67.5F, shield_4);
  		setNewShieldHitboxPos(animationTicks + 90F, shield_5);
  		setNewShieldHitboxPos(-animationTicks + 112.5F, shield_6);
  		setNewShieldHitboxPos(animationTicks + 135F, shield_7);
  		setNewShieldHitboxPos(-animationTicks + 157F, shield_8);
  
  		setNewShieldHitboxPos(animationTicks + 180F, shield_9);
  		setNewShieldHitboxPos(-animationTicks + 202.5F, shield_10);
  		setNewShieldHitboxPos(animationTicks + 225F, shield_11);
  		setNewShieldHitboxPos(-animationTicks + 247.5F, shield_12);
  		setNewShieldHitboxPos(animationTicks + 270F, shield_13);
  		setNewShieldHitboxPos(-animationTicks + 292.5F, shield_14);
  		setNewShieldHitboxPos(animationTicks + 315F, shield_15);
  		setNewShieldHitboxPos(-animationTicks + 337.5F, shield_16);
  
  		target_north.setPosition(posX, posY + 3D, posZ - 0.75D);
  		target_east.setPosition(posX + 0.75D, posY + 3D, posZ);
  		target_south.setPosition(posX, posY + 3D, posZ + 0.75D);
  		target_west.setPosition(posX - 0.75D, posY + 3D, posZ);
  		bottom.setPosition(posX, posY, posZ);
  
  		if (isMoving()) {
  			if (isSlow())
  				animationTicksChain++;
  			else
  				animationTicksChain += 8;
  			if(getHangingChains() != null)
  				getHangingChains().setProgress(getProgress());
  
  			if (!isRaising() && getProgress() < MAX_PROGRESS) {
  				move(MoverType.SELF, 0D, -MOVE_UNIT * 8D, 0D);
  				setProgress(getProgress() + 8);
  
  				if (getHangingChains() != null) {
  					getHangingChains().setMoving(true);
  					getHangingChains().setSlow(false);
  				}
  
  				if (getGroundChains() != null) {
  					for (TileEntityDecayPitGroundChain chain : getGroundChains()) {
  						chain.setRaising(true);
  						chain.setMoving(true);
  						chain.setSlow(false);
  					}
  				}
  			}
  
  			if (isRaising() && getProgress() > MIN_PROGRESS) {
  				move(MoverType.SELF, 0D, + MOVE_UNIT, 0D);
  				setProgress(getProgress() - 1);
  
  				if (getHangingChains() != null) {
  					getHangingChains().setMoving(true);
  					getHangingChains().setSlow(true);
  				}
  
  				if (getGroundChains() != null) {
  					for (TileEntityDecayPitGroundChain chain : getGroundChains()) {
  						chain.setRaising(false);
  						chain.setMoving(true);
  						chain.setSlow(true);
  					}
  				}
  			}
  
  		}
  
  		if (animationTicksChainPrev >= 128) {
  			animationTicksChain = animationTicksChainPrev = 0;
  			setMoving(false);
  		}
  
  		if (getProgress() > MAX_PROGRESS)
  			setProgress(MAX_PROGRESS);
  
  		if (getProgress() < MIN_PROGRESS)
  			setProgress(MIN_PROGRESS);
  
  		if (!getEntityWorld().isRemote) { // upsy-daisy
  			if (getProgress() > MIN_PROGRESS && getEntityWorld().getTotalWorldTime() % 400 == 0 && attackDamageTicks == 0)
  				moveUp();
  
  			TileEntityDecayPitControl control = this.getControl();
  
  			if (control != null && getEntityWorld().getTotalWorldTime() % 10 == 0) {
  				if (getProgress() < 128)
  					control.setSpawnType(0);
  				if (getProgress() >= 128 && getProgress() < 256)
  					control.setSpawnType(1);
  				if (getProgress() >= 256 && getProgress() < 384)
  					control.setSpawnType(2);
  				if (getProgress() >= 384 && getProgress() < 512)
  					control.setSpawnType(3);
  				if (getProgress() >= 512 && getProgress() < 640)
  					control.setSpawnType(4);
  				if (getProgress() >= 640)
  					control.setSpawnType(5);
  			}
  
  			if (control != null && control.getSpawnType() == 5) {
  				TileEntityDecayPitHangingChain hangingChains = this.getHangingChains();
  
  				if (hangingChains != null) {
  					hangingChains.setBroken(true);
  					hangingChains.setMoving(true);
  					hangingChains.setSlow(false);
  					hangingChains.updateBlock();
  				}
  
  				if (getGroundChains() != null) {
  					for (TileEntityDecayPitGroundChain chain : getGroundChains()) {
  						chain.setBroken(true);
  						chain.setRaising(false);
  						chain.setMoving(true);
  						chain.setSlow(false);
  						chain.updateBlock();
  					}
  				}
  				setDead(); // TODO some particles to show the bobbing shields break
  			}
  		}
  
  		if(!this.world.isRemote && this.isEntityAlive()) {
  			for(int i = 0; i < this.dummies.length; i++) {
  				DummyPart dummy = this.dummies[i];
  
  				if(dummy == null || !dummy.isEntityAlive()) {
  					Entity multipart = parts[i];
  
  					if(multipart instanceof MultiPartEntityPart) {
  						this.dummies[i] = dummy = new DummyPart(this.world, (MultiPartEntityPart) multipart);
  						this.world.spawnEntity(dummy);
  					}
  				} else {
  					dummy.updatePositioning();
  				}
  			}
  		}
  	}
  
  	protected void setHangingLength(EntityDecayPitTargetPart chain, float extended) {
  		chain.height = extended;
  		AxisAlignedBB axisalignedbb = new AxisAlignedBB(chain.posX - chain.width * 0.5D, posY + height, chain.posZ - chain.width * 0.5D, chain.posX + chain.width * 0.5D, posY + height + 2F + getProgress() * MOVE_UNIT, chain.posZ + chain.width * 0.5D);
  		chain.setEntityBoundingBox(axisalignedbb);
  		chain.onUpdate();
  	}
  
  	protected void setNewShieldHitboxPos(float animationTicks, EntityDecayPitTargetPart shield) {
  		double a = Math.toRadians(animationTicks);
  		double offSetX = -Math.sin(a) * 2.825D;
  		double offSetZ = Math.cos(a) * 2.825D;
  		float wobble = 0F;
  		if (shield == shield_1 || shield == shield_3 || shield == shield_5 || shield == shield_7 || shield == shield_9 || shield == shield_11 || shield == shield_13 || shield == shield_15)
  			wobble = MathHelper.sin(animationTicks * 0.14F) * 1.2F;
  		else
  			wobble = -MathHelper.sin(animationTicks * 0.14F) * 1.2F;
  		float squarePoint = Math.signum(wobble);
  		if(squarePoint == -1F)
  			wobble = 0F;
  		shield.setPosition(posX + offSetX, target_north.posY + target_north.height / 2.0D - shield.height + wobble, posZ + offSetZ);
  		shield.rotationYaw = animationTicks + 180F;
  
  		while(shield.rotationYaw - shield.prevRotationYaw < -180.0F) {
  			shield.prevRotationYaw -= 360.0F;
          }
          while(shield.rotationYaw - shield.prevRotationYaw >= 180.0F) {
          	shield.prevRotationYaw += 360.0F;
          }
  	}
  
  	@Override
  	public void setDead() {
  		// TODO Not this, will add something better, this is a placeholder test. ;P
  		/*
  		  for(EntityDecayPitTargetPart shieldPart : parts)
  		  	if(shieldPart.isShield)
  		  		getEntityWorld().playEvent(null, 2001, shieldPart.getPosition(), Block.getIdFromBlock(BlockRegistry.SMOOTH_PITSTONE));
  		 */
  		super.setDead();
  	}
  
  	@Override
  	public boolean canBePushed() {
  		return false;
  	}
  
  	@Override
  	public boolean canBeCollidedWith() {
  		return false;
  	}
  
  	@Override
  	@Nullable
  	public Entity[] getParts() {
  		return parts;
  	}
  
  	@Override
  	public void addVelocity(double x, double y, double z) {
  		motionX = 0D;
  		motionY = 0D;
  		motionZ = 0D;
  	}
  
  	@Override
  	public boolean getIsInvulnerable() {
  		return false;
  	}
  
  	@Override
  	public boolean attackEntityFrom(DamageSource source, float damage) {
  		return false;
  	}
  
  	@Override
  	public boolean attackEntityFromPart(MultiPartEntityPart part, DamageSource source, float damage) {
  		boolean wasBlocked = false;
  		
  		if(source.isExplosion())
  			return false;
  		
  		if(source instanceof EntityDamageSource) {
  			EntityDamageSource entityDamage = (EntityDamageSource) source;
  			
  			Entity sourceEntity = entityDamage.getTrueSource();
  			Entity immediateEntity = entityDamage.getImmediateSource();
  
  			Entity attackingEntity = immediateEntity != null ? immediateEntity : sourceEntity;
  			
  			if(attackingEntity == null) {
  				wasBlocked = true;
  			} else {
  				Vec3d pos = new Vec3d(attackingEntity.posX, attackingEntity.posY + attackingEntity.getEyeHeight(), attackingEntity.posZ);
  				
  				Vec3d ray;
  				if(attackingEntity instanceof EntityLivingBase) {
  					ray = attackingEntity.getLookVec();
  				} else {
  					ray = new Vec3d(attackingEntity.motionX, attackingEntity.motionY, attackingEntity.motionZ).normalize();
  				}
  				
  				EntityDecayPitTargetPart hitShield = this.rayTraceShields(pos, ray);
  				if(hitShield != null) {
  					wasBlocked = true;
  				}
  			}
  		}
  
  		if(part == target_north && !wasBlocked) {
  			if(!this.world.isRemote) {
  				if(getTargetNActive()) {
  					setTargetNActive(false);
  					playHitSound(getWorld(), target_north.getPosition());
  				}
  				if(getAllTargetsHit())
  					moveDown();
  				this.world.setEntityState(this, EVENT_ATTACK_DAMAGE);
  			}
  			return true;
  		}
  		else if(part == target_east && !wasBlocked) {
  			if(!this.world.isRemote) {
  				if(getTargetEActive()) {
  					setTargetEActive(false);
  					playHitSound(getWorld(), target_east.getPosition());
  				}
  				if(getAllTargetsHit())
  					moveDown();
  				this.world.setEntityState(this, EVENT_ATTACK_DAMAGE);
  			}
  			return true;
  		}
  		else if(part == target_south && !wasBlocked) {
  			if(!this.world.isRemote) {
  				if(getTargetSActive()) {
  					setTargetSActive(false);
  					playHitSound(getWorld(), target_south.getPosition());
  				}
  				if(getAllTargetsHit())
  					moveDown();
  				this.world.setEntityState(this, EVENT_ATTACK_DAMAGE);
  			}
  			return true;
  		}
  		else if(part == target_west && !wasBlocked) {
  			if(!this.world.isRemote) {
  				if(getTargetWActive()) {
  					setTargetWActive(false);
  					playHitSound(getWorld(), target_west.getPosition());
  				}
  				if(getAllTargetsHit())
  					moveDown();
  				this.world.setEntityState(this, EVENT_ATTACK_DAMAGE);
  			}
  			return true;
  		}
  		else if(wasBlocked) {
  			if(!this.world.isRemote) {
  				if(source instanceof EntityDamageSourceIndirect) {
  					Entity sourceEntity = ((EntityDamageSourceIndirect) source).getTrueSource();
  					if(sourceEntity != null && !world.isAirBlock(sourceEntity.getPosition().down())) {
  						EntityRootGrabber grabber = new EntityRootGrabber(this.world, true);
  						grabber.setPosition(source.getTrueSource().getPosition().down(), 40);
  						getEntityWorld().spawnEntity(grabber);
  					}
  				}
  				this.moveUp();
  				this.world.setEntityState(this, EVENT_ATTACK_BLOCKED);
  			}
  			return false;
  		}
  
  		return false;
  	}
  	
  	public void playHitSound(World world, BlockPos pos) {
  		getWorld().playSound(null, getPosition(), SoundRegistry.BEAM_ACTIVATE, SoundCategory.HOSTILE, 0.5F, 1F);
  	}
  
  	public void playDropSound(World world, BlockPos pos) {
  		getWorld().playSound(null, getPosition(), SoundRegistry.PLUG_HIT, SoundCategory.HOSTILE, 1F, 1F);
  	}
  
  	private boolean getAllTargetsHit() {
  		return !getTargetNActive() && !getTargetEActive() && !getTargetSActive() && !getTargetWActive();
  	}
  
  	@Nullable
  	public EntityDecayPitTargetPart rayTraceShields(Vec3d pos, Vec3d dir) {
  		Vec3d ray = dir.normalize().scale(3);
  		
  		float shieldSize = 0.6F;
  		
  		Vec3d v0 = new Vec3d(-shieldSize, -shieldSize, 0);
  		Vec3d v1 = new Vec3d(shieldSize, -shieldSize, 0);
  		Vec3d v2 = new Vec3d(shieldSize, shieldSize, 0);
  		Vec3d v3 = new Vec3d(-shieldSize, shieldSize, 0);
  		
  		for(EntityDecayPitTargetPart shieldPart : parts) {
  			if(shieldPart.isShield) {
  				Vec3d center = shieldPart.getPositionVector().add(0, shieldPart.height / 2, 0);
  				
  				this.rotationMatrix.setRotations(0, (float)Math.toRadians(shieldPart.rotationYaw), 0);
  				
  				Vec3d relPos = this.rotationMatrix.transformVec(pos.subtract(center), Vec3d.ZERO);;
  				Vec3d relRay = this.rotationMatrix.transformVec(ray, Vec3d.ZERO);
  				
  				if(EntityFortressBoss.rayTraceTriangle(relPos, relRay, v0, v1, v2) || EntityFortressBoss.rayTraceTriangle(relPos, relRay, v2, v3, v0)) {
  					return shieldPart;
  				}
  			}
  		}
  		
  		return null;
  	}
  	
  	@Override
  	public void handleStatusUpdate(byte id) {
  		super.handleStatusUpdate(id);
  		
  		if(id == EVENT_ATTACK_DAMAGE) {
  			this.attackDamageTicks = 40;
  		}
  	}
  	
  	private void moveUp() {
  		if (getProgress() > MIN_PROGRESS) {
  			setRaising(true);
  			setMoving(true);
  			setSlow(true);
  		}
  	}
  
  	private void moveDown() {
  		if (getProgress() < MAX_PROGRESS) {
  			setRaising(false);
  			setMoving(true);
  			setSlow(false);
  			setTargetNActive(true);
  			setTargetEActive(true);
  			setTargetSActive(true);
  			setTargetWActive(true);
  		}
  		playDropSound(getWorld(), getPosition());
  	}
  
  	public TileEntityDecayPitHangingChain getHangingChains() {
  		TileEntityDecayPitHangingChain tile = null;
  		for (int x = -1; x < 1; x++)
  			for (int y = 0; y < 15; y++)
  				for (int z = -1; z < 1; z++) {
  					if (getWorld().getTileEntity(getPosition().add(x, y, z)) instanceof TileEntityDecayPitHangingChain) {
  						tile = (TileEntityDecayPitHangingChain) getWorld().getTileEntity(getPosition().add(x, y, z));
  						tile.setProgress(getProgress());
  					}
  				}
  		return tile;
  	}
  
  	public TileEntityDecayPitControl getControl() {
  		TileEntityDecayPitControl tile = null;
  		for (int x = -1; x < 1; x++)
  			for (int y = -15; y < 0; y++)
  				for (int z = -1; z < 1; z++) {
  					if (getWorld().getTileEntity(getPosition().add(x, y, z)) instanceof TileEntityDecayPitControl)
  						tile = (TileEntityDecayPitControl) getWorld().getTileEntity(getPosition().add(x, y, z));
  				}
  		return tile;
  	}
  
  	public List<TileEntityDecayPitGroundChain> getGroundChains() {
  		TileEntityDecayPitGroundChain tile = null;
  		List<TileEntityDecayPitGroundChain> chains = new ArrayList<TileEntityDecayPitGroundChain>();
  		BlockPos posEntity = getPosition();
  		Iterable<BlockPos> blocks = BlockPos.getAllInBox(posEntity.add(-12.0F, 3F, -12F), posEntity.add(12F, 9F, 12F));
  		for (BlockPos pos : blocks)
  			if (getWorld().getTileEntity(pos) instanceof TileEntityDecayPitGroundChain) {
  				tile = (TileEntityDecayPitGroundChain) getWorld().getTileEntity(pos);
  				chains.add(tile);
  			}
  		return chains;
  	}
  
  	public void setProgress(int progress) {
  		dataManager.set(PROGRESS, progress);
  	}
  
  	public int getProgress() {
  		return dataManager.get(PROGRESS);
  	}
  
  	public void setRaising(boolean raising) {
  		dataManager.set(IS_RAISING, raising);
  	}
  
  	public boolean isRaising() {
  		return dataManager.get(IS_RAISING);
  	}
  
  	public void setMoving(boolean moving) {
  		dataManager.set(IS_MOVING, moving);
  	}
  	
  	public boolean isMoving() {
  		return dataManager.get(IS_MOVING);
  	}
  
  	public void setSlow(boolean slow) {
  		dataManager.set(IS_SLOW, slow);
  	}
  
  	public boolean isSlow() {
  		return dataManager.get(IS_SLOW);
  	}
  
  	public void setTargetNActive(boolean active) {
  		dataManager.set(TARGET_N_ACTIVE, active);
  	}
  
  	public boolean getTargetNActive() {
  		return dataManager.get(TARGET_N_ACTIVE);
  	}
  
  	public void setTargetEActive(boolean active) {
  		dataManager.set(TARGET_E_ACTIVE, active);
  	}
  
  	public boolean getTargetEActive() {
  		return dataManager.get(TARGET_E_ACTIVE);
  	}
  
  	public void setTargetWActive(boolean active) {
  		dataManager.set(TARGET_W_ACTIVE, active);
  	}
  
  	public boolean getTargetWActive() {
  		return dataManager.get(TARGET_W_ACTIVE);
  	}
  
  	public void setTargetSActive(boolean active) {
  		dataManager.set(TARGET_S_ACTIVE, active);
  	}
  
  	public boolean getTargetSActive() {
  		return dataManager.get(TARGET_S_ACTIVE);
  	}
  
  	@Override
  	public World getWorld() {
  		return getEntityWorld();
  	}
  
      public boolean canEntityBeSeen(Entity entity) {
          return getEntityWorld().rayTraceBlocks(new Vec3d(posX, posY + (double)getEyeHeight(), posZ), new Vec3d(entity.posX, entity.posY + (double)entity.getEyeHeight(), entity.posZ), false, true, false) == null;
      }
  
  	@Override
  	protected void readEntityFromNBT(NBTTagCompound nbt) {
  		setProgress(nbt.getInteger("progress"));
  		setTargetNActive(nbt.getBoolean("target_north"));
  		setTargetEActive(nbt.getBoolean("target_east"));
  		setTargetWActive(nbt.getBoolean("target_west"));
  		setTargetSActive(nbt.getBoolean("target_south"));
  	}
  
  	@Override
  	protected void writeEntityToNBT(NBTTagCompound nbt) {
  		nbt.setInteger("progress", getProgress());
  		nbt.setBoolean("target_north", getTargetNActive());
  		nbt.setBoolean("target_east", getTargetEActive());
  		nbt.setBoolean("target_west", getTargetWActive());
  		nbt.setBoolean("target_south", getTargetSActive());
  	}
  
  	@SideOnly(Side.CLIENT)
  	@Override
  	public AxisAlignedBB getRenderBoundingBox() {
  		return this.getEntityBoundingBox().grow(2);
  	}
  
  	@SideOnly(Side.CLIENT)
  	@Override
  	public int getBrightnessForRender() {
  		return 15728880;
  	}
  
  	@Override
  	public float getBrightness() {
  		return 1.0F;
  	}
  }