001package net.minecraft.entity.item;
002
003import cpw.mods.fml.relauncher.Side;
004import cpw.mods.fml.relauncher.SideOnly;
005import java.util.ArrayList;
006import java.util.Iterator;
007import net.minecraft.block.Block;
008import net.minecraft.block.BlockSand;
009import net.minecraft.block.ITileEntityProvider;
010import net.minecraft.crash.CrashReportCategory;
011import net.minecraft.entity.Entity;
012import net.minecraft.item.ItemStack;
013import net.minecraft.nbt.NBTBase;
014import net.minecraft.nbt.NBTTagCompound;
015import net.minecraft.tileentity.TileEntity;
016import net.minecraft.util.DamageSource;
017import net.minecraft.util.MathHelper;
018import net.minecraft.world.World;
019
020public class EntityFallingSand extends Entity
021{
022    public int blockID;
023    public int metadata;
024
025    /** How long the block has been falling for. */
026    public int fallTime;
027    public boolean shouldDropItem;
028    private boolean isBreakingAnvil;
029    private boolean isAnvil;
030
031    /** Maximum amount of damage dealt to entities hit by falling block */
032    private int fallHurtMax;
033
034    /** Actual damage dealt to entities hit by falling block */
035    private float fallHurtAmount;
036    public NBTTagCompound field_98051_e;
037
038    public EntityFallingSand(World par1World)
039    {
040        super(par1World);
041        this.fallTime = 0;
042        this.shouldDropItem = true;
043        this.isBreakingAnvil = false;
044        this.isAnvil = false;
045        this.fallHurtMax = 40;
046        this.fallHurtAmount = 2.0F;
047        this.field_98051_e = null;
048    }
049
050    public EntityFallingSand(World par1World, double par2, double par4, double par6, int par8)
051    {
052        this(par1World, par2, par4, par6, par8, 0);
053    }
054
055    public EntityFallingSand(World par1World, double par2, double par4, double par6, int par8, int par9)
056    {
057        super(par1World);
058        this.fallTime = 0;
059        this.shouldDropItem = true;
060        this.isBreakingAnvil = false;
061        this.isAnvil = false;
062        this.fallHurtMax = 40;
063        this.fallHurtAmount = 2.0F;
064        this.field_98051_e = null;
065        this.blockID = par8;
066        this.metadata = par9;
067        this.preventEntitySpawning = true;
068        this.setSize(0.98F, 0.98F);
069        this.yOffset = this.height / 2.0F;
070        this.setPosition(par2, par4, par6);
071        this.motionX = 0.0D;
072        this.motionY = 0.0D;
073        this.motionZ = 0.0D;
074        this.prevPosX = par2;
075        this.prevPosY = par4;
076        this.prevPosZ = par6;
077    }
078
079    /**
080     * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
081     * prevent them from trampling crops
082     */
083    protected boolean canTriggerWalking()
084    {
085        return false;
086    }
087
088    protected void entityInit() {}
089
090    /**
091     * Returns true if other Entities should be prevented from moving through this Entity.
092     */
093    public boolean canBeCollidedWith()
094    {
095        return !this.isDead;
096    }
097
098    /**
099     * Called to update the entity's position/logic.
100     */
101    public void onUpdate()
102    {
103        if (this.blockID == 0)
104        {
105            this.setDead();
106        }
107        else
108        {
109            this.prevPosX = this.posX;
110            this.prevPosY = this.posY;
111            this.prevPosZ = this.posZ;
112            ++this.fallTime;
113            this.motionY -= 0.03999999910593033D;
114            this.moveEntity(this.motionX, this.motionY, this.motionZ);
115            this.motionX *= 0.9800000190734863D;
116            this.motionY *= 0.9800000190734863D;
117            this.motionZ *= 0.9800000190734863D;
118
119            if (!this.worldObj.isRemote)
120            {
121                int i = MathHelper.floor_double(this.posX);
122                int j = MathHelper.floor_double(this.posY);
123                int k = MathHelper.floor_double(this.posZ);
124
125                if (this.fallTime == 1)
126                {
127                    if (this.worldObj.getBlockId(i, j, k) != this.blockID)
128                    {
129                        this.setDead();
130                        return;
131                    }
132
133                    this.worldObj.func_94571_i(i, j, k);
134                }
135
136                if (this.onGround)
137                {
138                    this.motionX *= 0.699999988079071D;
139                    this.motionZ *= 0.699999988079071D;
140                    this.motionY *= -0.5D;
141
142                    if (this.worldObj.getBlockId(i, j, k) != Block.pistonMoving.blockID)
143                    {
144                        this.setDead();
145
146                        if (!this.isBreakingAnvil && this.worldObj.canPlaceEntityOnSide(this.blockID, i, j, k, true, 1, (Entity)null, (ItemStack)null) && !BlockSand.canFallBelow(this.worldObj, i, j - 1, k) && this.worldObj.setBlockAndMetadataWithNotify(i, j, k, this.blockID, this.metadata, 3))
147                        {
148                            if (Block.blocksList[this.blockID] instanceof BlockSand)
149                            {
150                                ((BlockSand)Block.blocksList[this.blockID]).onFinishFalling(this.worldObj, i, j, k, this.metadata);
151                            }
152
153                            if (this.field_98051_e != null && Block.blocksList[this.blockID] instanceof ITileEntityProvider)
154                            {
155                                TileEntity tileentity = this.worldObj.getBlockTileEntity(i, j, k);
156
157                                if (tileentity != null)
158                                {
159                                    NBTTagCompound nbttagcompound = new NBTTagCompound();
160                                    tileentity.writeToNBT(nbttagcompound);
161                                    Iterator iterator = this.field_98051_e.getTags().iterator();
162
163                                    while (iterator.hasNext())
164                                    {
165                                        NBTBase nbtbase = (NBTBase)iterator.next();
166
167                                        if (!nbtbase.getName().equals("x") && !nbtbase.getName().equals("y") && !nbtbase.getName().equals("z"))
168                                        {
169                                            nbttagcompound.setTag(nbtbase.getName(), nbtbase.copy());
170                                        }
171                                    }
172
173                                    tileentity.readFromNBT(nbttagcompound);
174                                    tileentity.onInventoryChanged();
175                                }
176                            }
177                        }
178                        else if (this.shouldDropItem && !this.isBreakingAnvil)
179                        {
180                            this.entityDropItem(new ItemStack(this.blockID, 1, Block.blocksList[this.blockID].damageDropped(this.metadata)), 0.0F);
181                        }
182                    }
183                }
184                else if (this.fallTime > 100 && !this.worldObj.isRemote && (j < 1 || j > 256) || this.fallTime > 600)
185                {
186                    if (this.shouldDropItem)
187                    {
188                        this.entityDropItem(new ItemStack(this.blockID, 1, Block.blocksList[this.blockID].damageDropped(this.metadata)), 0.0F);
189                    }
190
191                    this.setDead();
192                }
193            }
194        }
195    }
196
197    /**
198     * Called when the mob is falling. Calculates and applies fall damage.
199     */
200    protected void fall(float par1)
201    {
202        if (this.isAnvil)
203        {
204            int i = MathHelper.ceiling_float_int(par1 - 1.0F);
205
206            if (i > 0)
207            {
208                ArrayList arraylist = new ArrayList(this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox));
209                DamageSource damagesource = this.blockID == Block.anvil.blockID ? DamageSource.anvil : DamageSource.fallingBlock;
210                Iterator iterator = arraylist.iterator();
211
212                while (iterator.hasNext())
213                {
214                    Entity entity = (Entity)iterator.next();
215                    entity.attackEntityFrom(damagesource, Math.min(MathHelper.floor_float((float)i * this.fallHurtAmount), this.fallHurtMax));
216                }
217
218                if (this.blockID == Block.anvil.blockID && (double)this.rand.nextFloat() < 0.05000000074505806D + (double)i * 0.05D)
219                {
220                    int j = this.metadata >> 2;
221                    int k = this.metadata & 3;
222                    ++j;
223
224                    if (j > 2)
225                    {
226                        this.isBreakingAnvil = true;
227                    }
228                    else
229                    {
230                        this.metadata = k | j << 2;
231                    }
232                }
233            }
234        }
235    }
236
237    /**
238     * (abstract) Protected helper method to write subclass entity data to NBT.
239     */
240    protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
241    {
242        par1NBTTagCompound.setByte("Tile", (byte)this.blockID);
243        par1NBTTagCompound.setInteger("TileID", this.blockID);
244        par1NBTTagCompound.setByte("Data", (byte)this.metadata);
245        par1NBTTagCompound.setByte("Time", (byte)this.fallTime);
246        par1NBTTagCompound.setBoolean("DropItem", this.shouldDropItem);
247        par1NBTTagCompound.setBoolean("HurtEntities", this.isAnvil);
248        par1NBTTagCompound.setFloat("FallHurtAmount", this.fallHurtAmount);
249        par1NBTTagCompound.setInteger("FallHurtMax", this.fallHurtMax);
250
251        if (this.field_98051_e != null)
252        {
253            par1NBTTagCompound.setCompoundTag("TileEntityData", this.field_98051_e);
254        }
255    }
256
257    /**
258     * (abstract) Protected helper method to read subclass entity data from NBT.
259     */
260    protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
261    {
262        if (par1NBTTagCompound.hasKey("TileID"))
263        {
264            this.blockID = par1NBTTagCompound.getInteger("TileID");
265        }
266        else
267        {
268            this.blockID = par1NBTTagCompound.getByte("Tile") & 255;
269        }
270
271        this.metadata = par1NBTTagCompound.getByte("Data") & 255;
272        this.fallTime = par1NBTTagCompound.getByte("Time") & 255;
273
274        if (par1NBTTagCompound.hasKey("HurtEntities"))
275        {
276            this.isAnvil = par1NBTTagCompound.getBoolean("HurtEntities");
277            this.fallHurtAmount = par1NBTTagCompound.getFloat("FallHurtAmount");
278            this.fallHurtMax = par1NBTTagCompound.getInteger("FallHurtMax");
279        }
280        else if (this.blockID == Block.anvil.blockID)
281        {
282            this.isAnvil = true;
283        }
284
285        if (par1NBTTagCompound.hasKey("DropItem"))
286        {
287            this.shouldDropItem = par1NBTTagCompound.getBoolean("DropItem");
288        }
289
290        if (par1NBTTagCompound.hasKey("TileEntityData"))
291        {
292            this.field_98051_e = par1NBTTagCompound.getCompoundTag("TileEntityData");
293        }
294
295        if (this.blockID == 0)
296        {
297            this.blockID = Block.sand.blockID;
298        }
299    }
300
301    public void setIsAnvil(boolean par1)
302    {
303        this.isAnvil = par1;
304    }
305
306    public void func_85029_a(CrashReportCategory par1CrashReportCategory)
307    {
308        super.func_85029_a(par1CrashReportCategory);
309        par1CrashReportCategory.addCrashSection("Immitating block ID", Integer.valueOf(this.blockID));
310        par1CrashReportCategory.addCrashSection("Immitating block data", Integer.valueOf(this.metadata));
311    }
312
313    @SideOnly(Side.CLIENT)
314    public float getShadowSize()
315    {
316        return 0.0F;
317    }
318
319    @SideOnly(Side.CLIENT)
320    public World getWorld()
321    {
322        return this.worldObj;
323    }
324
325    @SideOnly(Side.CLIENT)
326
327    /**
328     * Return whether this entity should be rendered as on fire.
329     */
330    public boolean canRenderOnFire()
331    {
332        return false;
333    }
334}