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.playSound("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.isEntityInvulnerable()) 271 { 272 return false; 273 } 274 else if (this.func_92014_d() != null && this.func_92014_d().itemID == Item.netherStar.itemID && 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.itemID) 360 { 361 par1EntityPlayer.triggerAchievement(AchievementList.killCow); 362 } 363 364 if (var2.itemID == Item.diamond.itemID) 365 { 366 par1EntityPlayer.triggerAchievement(AchievementList.diamonds); 367 } 368 369 if (var2.itemID == Item.blazeRod.itemID) 370 { 371 par1EntityPlayer.triggerAchievement(AchievementList.blazeRod); 372 } 373 374 GameRegistry.onPickupNotification(par1EntityPlayer, this); 375 376 this.playSound("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 }