    001    package net.minecraft.entity.item;
    002
    003    import java.util.Iterator;
    004
    005    import net.minecraftforge.common.MinecraftForge;
    006    import net.minecraftforge.event.Event.Result;
    007    import net.minecraftforge.event.entity.item.ItemExpireEvent;
    008    import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
    009
    010    import cpw.mods.fml.common.registry.GameRegistry;
    011    import net.minecraft.block.Block;
    012    import net.minecraft.block.material.Material;
    013    import net.minecraft.entity.Entity;
    014    import net.minecraft.entity.player.EntityPlayer;
    015    import net.minecraft.item.Item;
    016    import net.minecraft.item.ItemStack;
    017    import net.minecraft.nbt.NBTTagCompound;
    018    import net.minecraft.stats.AchievementList;
    019    import net.minecraft.util.DamageSource;
    020    import net.minecraft.util.MathHelper;
    021    import net.minecraft.util.StatCollector;
    022    import net.minecraft.world.World;
    023
    024    public class EntityItem extends Entity
    025    {
    026        /**
    027         * The age of this EntityItem (used to animate it up and down as well as expire it)
    028         */
    029        public int age;
    030        public int delayBeforeCanPickup;
    031
    032        /** The health of this EntityItem. (For example, damage for tools) */
    033        private int health;
    034
    035        /** The EntityItem's random initial float height. */
    036        public float hoverStart;
    037
    038        /**
    039         * The maximum age of this EntityItem.  The item is expired once this is reached.
    040         */
    041        public int lifespan = 6000;
    042
    043        public EntityItem(World par1World, double par2, double par4, double par6)
    044        {
    045            super(par1World);
    046            this.age = 0;
    047            this.health = 5;
    048            this.hoverStart = (float)(Math.random() * Math.PI * 2.0D);
    049            this.setSize(0.25F, 0.25F);
    050            this.yOffset = this.height / 2.0F;
    051            this.setPosition(par2, par4, par6);
    052            this.rotationYaw = (float)(Math.random() * 360.0D);
    053            this.motionX = (double)((float)(Math.random() * 0.20000000298023224D - 0.10000000149011612D));
    054            this.motionY = 0.20000000298023224D;
    055            this.motionZ = (double)((float)(Math.random() * 0.20000000298023224D - 0.10000000149011612D));
    056        }
    057
    058        public EntityItem(World par1World, double par2, double par4, double par6, ItemStack par8ItemStack)
    059        {
    060            this(par1World, par2, par4, par6);
    061            this.func_92013_a(par8ItemStack);
    062            this.lifespan = (par8ItemStack.getItem() == null ? 6000 : par8ItemStack.getItem().getEntityLifespan(par8ItemStack, par1World));
    063        }
    064
    065        /**
    066         * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to
    067         * prevent them from trampling crops
    068         */
    069        protected boolean canTriggerWalking()
    070        {
    071            return false;
    072        }
    073
    074        public EntityItem(World par1World)
    075        {
    076            super(par1World);
    077            this.age = 0;
    078            this.health = 5;
    079            this.hoverStart = (float)(Math.random() * Math.PI * 2.0D);
    080            this.setSize(0.25F, 0.25F);
    081            this.yOffset = this.height / 2.0F;
    082        }
    083
    084        protected void entityInit()
    085        {
    086            this.getDataWatcher().addObjectByDataType(10, 5);
    087        }
    088
    089        /**
    090         * Called to update the entity's position/logic.
    091         */
    092        public void onUpdate()
    093        {
    094            super.onUpdate();
    095
    096            if (this.delayBeforeCanPickup > 0)
    097            {
    098                --this.delayBeforeCanPickup;
    099            }
    100
    101            this.prevPosX = this.posX;
    102            this.prevPosY = this.posY;
    103            this.prevPosZ = this.posZ;
    104            this.motionY -= 0.03999999910593033D;
    105            this.noClip = this.pushOutOfBlocks(this.posX, (this.boundingBox.minY + this.boundingBox.maxY) / 2.0D, this.posZ);
    106            this.moveEntity(this.motionX, this.motionY, this.motionZ);
    107            boolean var1 = (int)this.prevPosX != (int)this.posX || (int)this.prevPosY != (int)this.posY || (int)this.prevPosZ != (int)this.posZ;
    108
    109            if (var1 || this.ticksExisted % 25 == 0)
    110            {
    111                if (this.worldObj.getBlockMaterial(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)) == Material.lava)
    112                {
    113                    this.motionY = 0.20000000298023224D;
    114                    this.motionX = (double)((this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F);
    115                    this.motionZ = (double)((this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F);
    116                    this.func_85030_a("random.fizz", 0.4F, 2.0F + this.rand.nextFloat() * 0.4F);
    117                }
    118
    119                if (!this.worldObj.isRemote)
    120                {
    121                    this.func_85054_d();
    122                }
    123            }
    124
    125            float var2 = 0.98F;
    126
    127            if (this.onGround)
    128            {
    129                var2 = 0.58800006F;
    130                int var3 = this.worldObj.getBlockId(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.boundingBox.minY) - 1, MathHelper.floor_double(this.posZ));
    131
    132                if (var3 > 0)
    133                {
    134                    var2 = Block.blocksList[var3].slipperiness * 0.98F;
    135                }
    136            }
    137
    138            this.motionX *= (double)var2;
    139            this.motionY *= 0.9800000190734863D;
    140            this.motionZ *= (double)var2;
    141
    142            if (this.onGround)
    143            {
    144                this.motionY *= -0.5D;
    145            }
    146
    147            ++this.age;
    148
    149            ItemStack item = getDataWatcher().getWatchableObjectItemStack(10);
    150
    151            if (!this.worldObj.isRemote && this.age >= lifespan)
    152            {
    153                if (item != null)
    154                {
    155                    ItemExpireEvent event = new ItemExpireEvent(this, (item.getItem() == null ? 6000 : item.getItem().getEntityLifespan(item, worldObj)));
    156                    if (MinecraftForge.EVENT_BUS.post(event))
    157                    {
    158                        lifespan += event.extraLife;
    159                    }
    160                    else
    161                    {
    162                        this.setDead();
    163                    }
    164                }
    165                else
    166                {
    167                    this.setDead();
    168                }
    169            }
    170
    171            if (item != null && item.stackSize <= 0)
    172            {
    173                this.setDead();
    174            }
    175        }
    176
    177        private void func_85054_d()
    178        {
    179            Iterator var1 = this.worldObj.getEntitiesWithinAABB(EntityItem.class, this.boundingBox.expand(0.5D, 0.0D, 0.5D)).iterator();
    180
    181            while (var1.hasNext())
    182            {
    183                EntityItem var2 = (EntityItem)var1.next();
    184                this.combineItems(var2);
    185            }
    186        }
    187
    188        /**
    189         * Tries to merge this item with the item passed as the parameter. Returns true if successful. Either this item or
    190         * the other item will  be removed from the world.
    191         */
    192        public boolean combineItems(EntityItem par1EntityItem)
    193        {
    194            if (par1EntityItem == this)
    195            {
    196                return false;
    197            }
    198            else if (par1EntityItem.isEntityAlive() && this.isEntityAlive())
    199            {
    200                ItemStack var2 = this.func_92014_d();
    201                ItemStack var3 = par1EntityItem.func_92014_d();
    202
    203                if (var3.getItem() != var2.getItem())
    204                {
    205                    return false;
    206                }
    207                else if (var3.hasTagCompound() ^ var2.hasTagCompound())
    208                {
    209                    return false;
    210                }
    211                else if (var3.hasTagCompound() && !var3.getTagCompound().equals(var2.getTagCompound()))
    212                {
    213                    return false;
    214                }
    215                else if (var3.getItem().getHasSubtypes() && var3.getItemDamage() != var2.getItemDamage())
    216                {
    217                    return false;
    218                }
    219                else if (var3.stackSize < var2.stackSize)
    220                {
    221                    return par1EntityItem.combineItems(this);
    222                }
    223                else if (var3.stackSize + var2.stackSize > var3.getMaxStackSize())
    224                {
    225                    return false;
    226                }
    227                else
    228                {
    229                    var3.stackSize += var2.stackSize;
    230                    par1EntityItem.delayBeforeCanPickup = Math.max(par1EntityItem.delayBeforeCanPickup, this.delayBeforeCanPickup);
    231                    par1EntityItem.age = Math.min(par1EntityItem.age, this.age);
    232                    par1EntityItem.func_92013_a(var3);
    233                    this.setDead();
    234                    return true;
    235                }
    236            }
    237            else
    238            {
    239                return false;
    240            }
    241        }
    242
    243        public void func_70288_d()
    244        {
    245            this.age = 4800;
    246        }
    247
    248        /**
    249         * Returns if this entity is in water and will end up adding the waters velocity to the entity
    250         */
    251        public boolean handleWaterMovement()
    252        {
    253            return this.worldObj.handleMaterialAcceleration(this.boundingBox, Material.water, this);
    254        }
    255
    256        /**
    257         * Will deal the specified amount of damage to the entity if the entity isn't immune to fire damage. Args:
    258         * amountDamage
    259         */
    260        protected void dealFireDamage(int par1)
    261        {
    262            this.attackEntityFrom(DamageSource.inFire, par1);
    263        }
    264
    265        /**
    266         * Called when the entity is attacked.
    267         */
    268        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
    269        {
    270            if (this.func_85032_ar())
    271            {
    272                return false;
    273            }
    274            else if (this.func_92014_d() != null && this.func_92014_d().itemID == Item.netherStar.shiftedIndex && par1DamageSource == DamageSource.explosion)
    275            {
    276                return false;
    277            }
    278            else
    279            {
    280                this.setBeenAttacked();
    281                this.health -= par2;
    282
    283                if (this.health <= 0)
    284                {
    285                    this.setDead();
    286                }
    287
    288                return false;
    289            }
    290        }
    291
    292        /**
    293         * (abstract) Protected helper method to write subclass entity data to NBT.
    294         */
    295        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    296        {
    297            par1NBTTagCompound.setShort("Health", (short)((byte)this.health));
    298            par1NBTTagCompound.setShort("Age", (short)this.age);
    299            par1NBTTagCompound.setInteger("Lifespan", lifespan);
    300
    301            if (this.func_92014_d() != null)
    302            {
    303                par1NBTTagCompound.setCompoundTag("Item", this.func_92014_d().writeToNBT(new NBTTagCompound()));
    304            }
    305        }
    306
    307        /**
    308         * (abstract) Protected helper method to read subclass entity data from NBT.
    309         */
    310        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    311        {
    312            this.health = par1NBTTagCompound.getShort("Health") & 255;
    313            this.age = par1NBTTagCompound.getShort("Age");
    314            NBTTagCompound var2 = par1NBTTagCompound.getCompoundTag("Item");
    315            this.func_92013_a(ItemStack.loadItemStackFromNBT(var2));
    316
    317            ItemStack item = getDataWatcher().getWatchableObjectItemStack(10);
    318
    319            if (item == null || item.stackSize <= 0)
    320            {
    321                this.setDead();
    322            }
    323
    324            if (par1NBTTagCompound.hasKey("Lifespan"))
    325            {
    326                lifespan = par1NBTTagCompound.getInteger("Lifespan");
    327            }
    328        }
    329
    330        /**
    331         * Called by a player entity when they collide with an entity
    332         */
    333        public void onCollideWithPlayer(EntityPlayer par1EntityPlayer)
    334        {
    335            if (!this.worldObj.isRemote)
    336            {
    337                if (this.delayBeforeCanPickup > 0)
    338                {
    339                    return;
    340                }
    341
    342                EntityItemPickupEvent event = new EntityItemPickupEvent(par1EntityPlayer, this);
    343
    344                if (MinecraftForge.EVENT_BUS.post(event))
    345                {
    346                    return;
    347                }
    348
    349                ItemStack var2 = this.func_92014_d();
    350                int var3 = var2.stackSize;
    351
    352                if (this.delayBeforeCanPickup <= 0 && (event.getResult() == Result.ALLOW || var3 <= 0 || par1EntityPlayer.inventory.addItemStackToInventory(var2)))
    353                {
    354                    if (var2.itemID == Block.wood.blockID)
    355                    {
    356                        par1EntityPlayer.triggerAchievement(AchievementList.mineWood);
    357                    }
    358
    359                    if (var2.itemID == Item.leather.shiftedIndex)
    360                    {
    361                        par1EntityPlayer.triggerAchievement(AchievementList.killCow);
    362                    }
    363
    364                    if (var2.itemID == Item.diamond.shiftedIndex)
    365                    {
    366                        par1EntityPlayer.triggerAchievement(AchievementList.diamonds);
    367                    }
    368
    369                    if (var2.itemID == Item.blazeRod.shiftedIndex)
    370                    {
    371                        par1EntityPlayer.triggerAchievement(AchievementList.blazeRod);
    372                    }
    373
    374                    GameRegistry.onPickupNotification(par1EntityPlayer, this);
    375
    376                    this.func_85030_a("random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F);
    377                    par1EntityPlayer.onItemPickup(this, var3);
    378
    379                    if (var2.stackSize <= 0)
    380                    {
    381                        this.setDead();
    382                    }
    383                }
    384            }
    385        }
    386
    387        /**
    388         * Gets the username of the entity.
    389         */
    390        public String getEntityName()
    391        {
    392            return StatCollector.translateToLocal("item." + this.func_92014_d().getItemName());
    393        }
    394
    395        /**
    396         * If returns false, the item will not inflict any damage against entities.
    397         */
    398        public boolean canAttackWithItem()
    399        {
    400            return false;
    401        }
    402
    403        /**
    404         * Teleports the entity to another dimension. Params: Dimension number to teleport to
    405         */
    406        public void travelToDimension(int par1)
    407        {
    408            super.travelToDimension(par1);
    409
    410            if (!this.worldObj.isRemote)
    411            {
    412                this.func_85054_d();
    413            }
    414        }
    415
    416        public ItemStack func_92014_d()
    417        {
    418            ItemStack var1 = this.getDataWatcher().getWatchableObjectItemStack(10);
    419
    420            if (var1 == null)
    421            {
    422                System.out.println("Item entity " + this.entityId + " has no item?!");
    423                return new ItemStack(Block.stone);
    424            }
    425            else
    426            {
    427                return var1;
    428            }
    429        }
    430
    431        public void func_92013_a(ItemStack par1ItemStack)
    432        {
    433            this.getDataWatcher().updateObject(10, par1ItemStack);
    434            this.getDataWatcher().func_82708_h(10);
    435        }
    436    }