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