001package net.minecraft.entity.item; 002 003import net.minecraft.entity.player.EntityPlayer; 004import net.minecraft.inventory.Container; 005import net.minecraft.inventory.IInventory; 006import net.minecraft.item.ItemStack; 007import net.minecraft.nbt.NBTTagCompound; 008import net.minecraft.nbt.NBTTagList; 009import net.minecraft.util.DamageSource; 010import net.minecraft.world.World; 011import net.minecraftforge.common.MinecraftForge; 012import net.minecraftforge.event.entity.minecart.MinecartInteractEvent; 013 014public abstract class EntityMinecartContainer extends EntityMinecart implements IInventory 015{ 016 private ItemStack[] minecartContainerItems = new ItemStack[36]; 017 018 /** 019 * When set to true, the minecart will drop all items when setDead() is called. When false (such as when travelling 020 * dimensions) it preserves its contents. 021 */ 022 private boolean dropContentsWhenDead = true; 023 024 public EntityMinecartContainer(World par1World) 025 { 026 super(par1World); 027 } 028 029 public EntityMinecartContainer(World par1World, double par2, double par4, double par6) 030 { 031 super(par1World, par2, par4, par6); 032 } 033 034 public void killMinecart(DamageSource par1DamageSource) 035 { 036 super.killMinecart(par1DamageSource); 037 038 for (int i = 0; i < this.getSizeInventory(); ++i) 039 { 040 ItemStack itemstack = this.getStackInSlot(i); 041 042 if (itemstack != null) 043 { 044 float f = this.rand.nextFloat() * 0.8F + 0.1F; 045 float f1 = this.rand.nextFloat() * 0.8F + 0.1F; 046 float f2 = this.rand.nextFloat() * 0.8F + 0.1F; 047 048 while (itemstack.stackSize > 0) 049 { 050 int j = this.rand.nextInt(21) + 10; 051 052 if (j > itemstack.stackSize) 053 { 054 j = itemstack.stackSize; 055 } 056 057 itemstack.stackSize -= j; 058 EntityItem entityitem = new EntityItem(this.worldObj, this.posX + (double)f, this.posY + (double)f1, this.posZ + (double)f2, new ItemStack(itemstack.itemID, j, itemstack.getItemDamage())); 059 float f3 = 0.05F; 060 entityitem.motionX = (double)((float)this.rand.nextGaussian() * f3); 061 entityitem.motionY = (double)((float)this.rand.nextGaussian() * f3 + 0.2F); 062 entityitem.motionZ = (double)((float)this.rand.nextGaussian() * f3); 063 this.worldObj.spawnEntityInWorld(entityitem); 064 } 065 } 066 } 067 } 068 069 /** 070 * Returns the stack in slot i 071 */ 072 public ItemStack getStackInSlot(int par1) 073 { 074 return this.minecartContainerItems[par1]; 075 } 076 077 /** 078 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a 079 * new stack. 080 */ 081 public ItemStack decrStackSize(int par1, int par2) 082 { 083 if (this.minecartContainerItems[par1] != null) 084 { 085 ItemStack itemstack; 086 087 if (this.minecartContainerItems[par1].stackSize <= par2) 088 { 089 itemstack = this.minecartContainerItems[par1]; 090 this.minecartContainerItems[par1] = null; 091 return itemstack; 092 } 093 else 094 { 095 itemstack = this.minecartContainerItems[par1].splitStack(par2); 096 097 if (this.minecartContainerItems[par1].stackSize == 0) 098 { 099 this.minecartContainerItems[par1] = null; 100 } 101 102 return itemstack; 103 } 104 } 105 else 106 { 107 return null; 108 } 109 } 110 111 /** 112 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - 113 * like when you close a workbench GUI. 114 */ 115 public ItemStack getStackInSlotOnClosing(int par1) 116 { 117 if (this.minecartContainerItems[par1] != null) 118 { 119 ItemStack itemstack = this.minecartContainerItems[par1]; 120 this.minecartContainerItems[par1] = null; 121 return itemstack; 122 } 123 else 124 { 125 return null; 126 } 127 } 128 129 /** 130 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). 131 */ 132 public void setInventorySlotContents(int par1, ItemStack par2ItemStack) 133 { 134 this.minecartContainerItems[par1] = par2ItemStack; 135 136 if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit()) 137 { 138 par2ItemStack.stackSize = this.getInventoryStackLimit(); 139 } 140 } 141 142 /** 143 * Called when an the contents of an Inventory change, usually 144 */ 145 public void onInventoryChanged() {} 146 147 /** 148 * Do not make give this method the name canInteractWith because it clashes with Container 149 */ 150 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) 151 { 152 return this.isDead ? false : par1EntityPlayer.getDistanceSqToEntity(this) <= 64.0D; 153 } 154 155 public void openChest() {} 156 157 public void closeChest() {} 158 159 /** 160 * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot. 161 */ 162 public boolean isStackValidForSlot(int par1, ItemStack par2ItemStack) 163 { 164 return true; 165 } 166 167 /** 168 * Returns the name of the inventory. 169 */ 170 public String getInvName() 171 { 172 return this.isInvNameLocalized() ? this.func_95999_t() : "container.minecart"; 173 } 174 175 /** 176 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't 177 * this more of a set than a get?* 178 */ 179 public int getInventoryStackLimit() 180 { 181 return 64; 182 } 183 184 /** 185 * Teleports the entity to another dimension. Params: Dimension number to teleport to 186 */ 187 public void travelToDimension(int par1) 188 { 189 this.dropContentsWhenDead = false; 190 super.travelToDimension(par1); 191 } 192 193 /** 194 * Will get destroyed next tick. 195 */ 196 public void setDead() 197 { 198 if (this.dropContentsWhenDead) 199 { 200 for (int i = 0; i < this.getSizeInventory(); ++i) 201 { 202 ItemStack itemstack = this.getStackInSlot(i); 203 204 if (itemstack != null) 205 { 206 float f = this.rand.nextFloat() * 0.8F + 0.1F; 207 float f1 = this.rand.nextFloat() * 0.8F + 0.1F; 208 float f2 = this.rand.nextFloat() * 0.8F + 0.1F; 209 210 while (itemstack.stackSize > 0) 211 { 212 int j = this.rand.nextInt(21) + 10; 213 214 if (j > itemstack.stackSize) 215 { 216 j = itemstack.stackSize; 217 } 218 219 itemstack.stackSize -= j; 220 EntityItem entityitem = new EntityItem(this.worldObj, this.posX + (double)f, this.posY + (double)f1, this.posZ + (double)f2, new ItemStack(itemstack.itemID, j, itemstack.getItemDamage())); 221 222 if (itemstack.hasTagCompound()) 223 { 224 entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy()); 225 } 226 227 float f3 = 0.05F; 228 entityitem.motionX = (double)((float)this.rand.nextGaussian() * f3); 229 entityitem.motionY = (double)((float)this.rand.nextGaussian() * f3 + 0.2F); 230 entityitem.motionZ = (double)((float)this.rand.nextGaussian() * f3); 231 this.worldObj.spawnEntityInWorld(entityitem); 232 } 233 } 234 } 235 } 236 237 super.setDead(); 238 } 239 240 /** 241 * (abstract) Protected helper method to write subclass entity data to NBT. 242 */ 243 protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound) 244 { 245 super.writeEntityToNBT(par1NBTTagCompound); 246 NBTTagList nbttaglist = new NBTTagList(); 247 248 for (int i = 0; i < this.minecartContainerItems.length; ++i) 249 { 250 if (this.minecartContainerItems[i] != null) 251 { 252 NBTTagCompound nbttagcompound1 = new NBTTagCompound(); 253 nbttagcompound1.setByte("Slot", (byte)i); 254 this.minecartContainerItems[i].writeToNBT(nbttagcompound1); 255 nbttaglist.appendTag(nbttagcompound1); 256 } 257 } 258 259 par1NBTTagCompound.setTag("Items", nbttaglist); 260 } 261 262 /** 263 * (abstract) Protected helper method to read subclass entity data from NBT. 264 */ 265 protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound) 266 { 267 super.readEntityFromNBT(par1NBTTagCompound); 268 NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items"); 269 this.minecartContainerItems = new ItemStack[this.getSizeInventory()]; 270 271 for (int i = 0; i < nbttaglist.tagCount(); ++i) 272 { 273 NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i); 274 int j = nbttagcompound1.getByte("Slot") & 255; 275 276 if (j >= 0 && j < this.minecartContainerItems.length) 277 { 278 this.minecartContainerItems[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1); 279 } 280 } 281 } 282 283 /** 284 * Called when a player interacts with a mob. e.g. gets milk from a cow, gets into the saddle on a pig. 285 */ 286 public boolean interact(EntityPlayer par1EntityPlayer) 287 { 288 if(MinecraftForge.EVENT_BUS.post(new MinecartInteractEvent(this, par1EntityPlayer))) 289 { 290 return true; 291 } 292 if (!this.worldObj.isRemote) 293 { 294 par1EntityPlayer.displayGUIChest(this); 295 } 296 297 return true; 298 } 299 300 protected void applyDrag() 301 { 302 int i = 15 - Container.func_94526_b(this); 303 float f = 0.98F + (float)i * 0.001F; 304 this.motionX *= (double)f; 305 this.motionY *= 0.0D; 306 this.motionZ *= (double)f; 307 } 308}