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 ItemExpireEvent event = new ItemExpireEvent(this, (item.getItem() == null ? 6000 : item.getItem().getEntityLifespan(item, worldObj))); 154 if (MinecraftForge.EVENT_BUS.post(event)) 155 { 156 lifespan += event.extraLife; 157 } 158 else 159 { 160 this.setDead(); 161 } 162 } 163 164 if (item == null || item.stackSize <= 0) 165 { 166 this.setDead(); 167 } 168 } 169 170 private void func_85054_d() 171 { 172 Iterator var1 = this.worldObj.getEntitiesWithinAABB(EntityItem.class, this.boundingBox.expand(0.5D, 0.0D, 0.5D)).iterator(); 173 174 while (var1.hasNext()) 175 { 176 EntityItem var2 = (EntityItem)var1.next(); 177 this.combineItems(var2); 178 } 179 } 180 181 /** 182 * Tries to merge this item with the item passed as the parameter. Returns true if successful. Either this item or 183 * the other item will be removed from the world. 184 */ 185 public boolean combineItems(EntityItem par1EntityItem) 186 { 187 if (par1EntityItem == this) 188 { 189 return false; 190 } 191 else if (par1EntityItem.isEntityAlive() && this.isEntityAlive()) 192 { 193 ItemStack var2 = this.func_92014_d(); 194 ItemStack var3 = par1EntityItem.func_92014_d(); 195 196 if (var3.getItem() != var2.getItem()) 197 { 198 return false; 199 } 200 else if (var3.hasTagCompound() ^ var2.hasTagCompound()) 201 { 202 return false; 203 } 204 else if (var3.hasTagCompound() && !var3.getTagCompound().equals(var2.getTagCompound())) 205 { 206 return false; 207 } 208 else if (var3.getItem().getHasSubtypes() && var3.getItemDamage() != var2.getItemDamage()) 209 { 210 return false; 211 } 212 else if (var3.stackSize < var2.stackSize) 213 { 214 return par1EntityItem.combineItems(this); 215 } 216 else if (var3.stackSize + var2.stackSize > var3.getMaxStackSize()) 217 { 218 return false; 219 } 220 else 221 { 222 var3.stackSize += var2.stackSize; 223 par1EntityItem.delayBeforeCanPickup = Math.max(par1EntityItem.delayBeforeCanPickup, this.delayBeforeCanPickup); 224 par1EntityItem.age = Math.min(par1EntityItem.age, this.age); 225 par1EntityItem.func_92013_a(var3); 226 this.setDead(); 227 return true; 228 } 229 } 230 else 231 { 232 return false; 233 } 234 } 235 236 public void func_70288_d() 237 { 238 this.age = 4800; 239 } 240 241 /** 242 * Returns if this entity is in water and will end up adding the waters velocity to the entity 243 */ 244 public boolean handleWaterMovement() 245 { 246 return this.worldObj.handleMaterialAcceleration(this.boundingBox, Material.water, this); 247 } 248 249 /** 250 * Will deal the specified amount of damage to the entity if the entity isn't immune to fire damage. Args: 251 * amountDamage 252 */ 253 protected void dealFireDamage(int par1) 254 { 255 this.attackEntityFrom(DamageSource.inFire, par1); 256 } 257 258 /** 259 * Called when the entity is attacked. 260 */ 261 public boolean attackEntityFrom(DamageSource par1DamageSource, int par2) 262 { 263 if (this.func_85032_ar()) 264 { 265 return false; 266 } 267 else if (this.func_92014_d() != null && this.func_92014_d().itemID == Item.netherStar.shiftedIndex && par1DamageSource == DamageSource.explosion) 268 { 269 return false; 270 } 271 else 272 { 273 this.setBeenAttacked(); 274 this.health -= par2; 275 276 if (this.health <= 0) 277 { 278 this.setDead(); 279 } 280 281 return false; 282 } 283 } 284 285 /** 286 * (abstract) Protected helper method to write subclass entity data to NBT. 287 */ 288 public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 289 { 290 par1NBTTagCompound.setShort("Health", (short)((byte)this.health)); 291 par1NBTTagCompound.setShort("Age", (short)this.age); 292 par1NBTTagCompound.setInteger("Lifespan", lifespan); 293 294 if (this.func_92014_d() != null) 295 { 296 par1NBTTagCompound.setCompoundTag("Item", this.func_92014_d().writeToNBT(new NBTTagCompound())); 297 } 298 } 299 300 /** 301 * (abstract) Protected helper method to read subclass entity data from NBT. 302 */ 303 public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 304 { 305 this.health = par1NBTTagCompound.getShort("Health") & 255; 306 this.age = par1NBTTagCompound.getShort("Age"); 307 NBTTagCompound var2 = par1NBTTagCompound.getCompoundTag("Item"); 308 this.func_92013_a(ItemStack.loadItemStackFromNBT(var2)); 309 310 ItemStack item = getDataWatcher().getWatchableObjectItemStack(10); 311 312 if (item == null || item.stackSize <= 0) 313 { 314 this.setDead(); 315 } 316 317 if (par1NBTTagCompound.hasKey("Lifespan")) 318 { 319 lifespan = par1NBTTagCompound.getInteger("Lifespan"); 320 } 321 } 322 323 /** 324 * Called by a player entity when they collide with an entity 325 */ 326 public void onCollideWithPlayer(EntityPlayer par1EntityPlayer) 327 { 328 if (!this.worldObj.isRemote) 329 { 330 if (this.delayBeforeCanPickup > 0) 331 { 332 return; 333 } 334 335 EntityItemPickupEvent event = new EntityItemPickupEvent(par1EntityPlayer, this); 336 337 if (MinecraftForge.EVENT_BUS.post(event)) 338 { 339 return; 340 } 341 342 ItemStack var2 = this.func_92014_d(); 343 int var3 = var2.stackSize; 344 345 if (this.delayBeforeCanPickup <= 0 && (event.getResult() == Result.ALLOW || var3 <= 0 || par1EntityPlayer.inventory.addItemStackToInventory(var2))) 346 { 347 if (var2.itemID == Block.wood.blockID) 348 { 349 par1EntityPlayer.triggerAchievement(AchievementList.mineWood); 350 } 351 352 if (var2.itemID == Item.leather.shiftedIndex) 353 { 354 par1EntityPlayer.triggerAchievement(AchievementList.killCow); 355 } 356 357 if (var2.itemID == Item.diamond.shiftedIndex) 358 { 359 par1EntityPlayer.triggerAchievement(AchievementList.diamonds); 360 } 361 362 if (var2.itemID == Item.blazeRod.shiftedIndex) 363 { 364 par1EntityPlayer.triggerAchievement(AchievementList.blazeRod); 365 } 366 367 GameRegistry.onPickupNotification(par1EntityPlayer, this); 368 369 this.func_85030_a("random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); 370 par1EntityPlayer.onItemPickup(this, var3); 371 372 if (var2.stackSize <= 0) 373 { 374 this.setDead(); 375 } 376 } 377 } 378 } 379 380 /** 381 * Gets the username of the entity. 382 */ 383 public String getEntityName() 384 { 385 return StatCollector.translateToLocal("item." + this.func_92014_d().getItemName()); 386 } 387 388 /** 389 * If returns false, the item will not inflict any damage against entities. 390 */ 391 public boolean canAttackWithItem() 392 { 393 return false; 394 } 395 396 /** 397 * Teleports the entity to another dimension. Params: Dimension number to teleport to 398 */ 399 public void travelToDimension(int par1) 400 { 401 super.travelToDimension(par1); 402 403 if (!this.worldObj.isRemote) 404 { 405 this.func_85054_d(); 406 } 407 } 408 409 public ItemStack func_92014_d() 410 { 411 ItemStack var1 = this.getDataWatcher().getWatchableObjectItemStack(10); 412 413 if (var1 == null) 414 { 415 System.out.println("Item entity " + this.entityId + " has no item?!"); 416 return new ItemStack(Block.stone); 417 } 418 else 419 { 420 return var1; 421 } 422 } 423 424 public void func_92013_a(ItemStack par1ItemStack) 425 { 426 this.getDataWatcher().updateObject(10, par1ItemStack); 427 this.getDataWatcher().func_82708_h(10); 428 } 429 }