    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 fallingBlockTileEntityData;
    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.fallingBlockTileEntityData = 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.fallingBlockTileEntityData = 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.setBlockToAir(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.setBlock(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.fallingBlockTileEntityData != 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.fallingBlockTileEntityData.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.fallingBlockTileEntityData != null)
    252        {
    253            par1NBTTagCompound.setCompoundTag("TileEntityData", this.fallingBlockTileEntityData);
    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.fallingBlockTileEntityData = 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}