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