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.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.getItem().getHasSubtypes() && par1EntityItem.item.getItemDamage() != this.item.getItemDamage())
163                {
164                    return false;
165                }
166                else if (par1EntityItem.item.stackSize < this.item.stackSize)
167                {
168                    return par1EntityItem.func_70289_a(this);
169                }
170                else if (par1EntityItem.item.stackSize + this.item.stackSize > par1EntityItem.item.getMaxStackSize())
171                {
172                    return false;
173                }
174                else
175                {
176                    par1EntityItem.item.stackSize += this.item.stackSize;
177                    par1EntityItem.delayBeforeCanPickup = Math.max(par1EntityItem.delayBeforeCanPickup, this.delayBeforeCanPickup);
178                    par1EntityItem.age = Math.min(par1EntityItem.age, this.age);
179                    this.setDead();
180                    return true;
181                }
182            }
183            else
184            {
185                return false;
186            }
187        }
188    
189        public void func_70288_d()
190        {
191            this.age = 4800;
192        }
193    
194        /**
195         * Returns if this entity is in water and will end up adding the waters velocity to the entity
196         */
197        public boolean handleWaterMovement()
198        {
199            return this.worldObj.handleMaterialAcceleration(this.boundingBox, Material.water, this);
200        }
201    
202        /**
203         * Will deal the specified amount of damage to the entity if the entity isn't immune to fire damage. Args:
204         * amountDamage
205         */
206        protected void dealFireDamage(int par1)
207        {
208            this.attackEntityFrom(DamageSource.inFire, par1);
209        }
210    
211        /**
212         * Called when the entity is attacked.
213         */
214        public boolean attackEntityFrom(DamageSource par1DamageSource, int par2)
215        {
216            this.setBeenAttacked();
217            this.health -= par2;
218    
219            if (this.health <= 0)
220            {
221                this.setDead();
222            }
223    
224            return false;
225        }
226    
227        /**
228         * (abstract) Protected helper method to write subclass entity data to NBT.
229         */
230        public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
231        {
232            par1NBTTagCompound.setShort("Health", (short)((byte)this.health));
233            par1NBTTagCompound.setShort("Age", (short)this.age);
234            par1NBTTagCompound.setInteger("Lifespan", lifespan);
235    
236            if (this.item != null)
237            {
238                par1NBTTagCompound.setCompoundTag("Item", this.item.writeToNBT(new NBTTagCompound()));
239            }
240        }
241    
242        /**
243         * (abstract) Protected helper method to read subclass entity data from NBT.
244         */
245        public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
246        {
247            this.health = par1NBTTagCompound.getShort("Health") & 255;
248            this.age = par1NBTTagCompound.getShort("Age");
249            NBTTagCompound var2 = par1NBTTagCompound.getCompoundTag("Item");
250            this.item = ItemStack.loadItemStackFromNBT(var2);
251    
252            if (this.item == null || this.item.stackSize <= 0)
253            {
254                this.setDead();
255            }
256    
257            if (par1NBTTagCompound.hasKey("Lifespan"))
258            {
259                lifespan = par1NBTTagCompound.getInteger("Lifespan");
260            }
261        }
262    
263        /**
264         * Called by a player entity when they collide with an entity
265         */
266        public void onCollideWithPlayer(EntityPlayer par1EntityPlayer)
267        {
268            if (!this.worldObj.isRemote)
269            {
270                if (this.delayBeforeCanPickup > 0)
271                {
272                    return;
273                }
274    
275                EntityItemPickupEvent event = new EntityItemPickupEvent(par1EntityPlayer, this);
276    
277                if (MinecraftForge.EVENT_BUS.post(event))
278                {
279                    return;
280                }
281    
282                int var2 = this.item.stackSize;
283    
284                if (this.delayBeforeCanPickup <= 0 && (event.isHandled() || var2 <= 0 || par1EntityPlayer.inventory.addItemStackToInventory(this.item)))
285                {
286                    if (this.item.itemID == Block.wood.blockID)
287                    {
288                        par1EntityPlayer.triggerAchievement(AchievementList.mineWood);
289                    }
290    
291                    if (this.item.itemID == Item.leather.shiftedIndex)
292                    {
293                        par1EntityPlayer.triggerAchievement(AchievementList.killCow);
294                    }
295    
296                    if (this.item.itemID == Item.diamond.shiftedIndex)
297                    {
298                        par1EntityPlayer.triggerAchievement(AchievementList.diamonds);
299                    }
300    
301                    if (this.item.itemID == Item.blazeRod.shiftedIndex)
302                    {
303                        par1EntityPlayer.triggerAchievement(AchievementList.blazeRod);
304                    }
305    
306                    GameRegistry.onPickupNotification(par1EntityPlayer, this);
307    
308                    this.worldObj.playSoundAtEntity(this, "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F);
309                    par1EntityPlayer.onItemPickup(this, var2);
310    
311                    if (this.item.stackSize <= 0)
312                    {
313                        this.setDead();
314                    }
315                }
316            }
317        }
318    
319        /**
320         * Gets the username of the entity.
321         */
322        public String getEntityName()
323        {
324            return StatCollector.translateToLocal("item." + this.item.getItemName());
325        }
326    
327        /**
328         * If returns false, the item will not inflict any damage against entities.
329         */
330        public boolean canAttackWithItem()
331        {
332            return false;
333        }
334    }