001package net.minecraft.tileentity; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.List; 006import net.minecraft.entity.player.EntityPlayer; 007import net.minecraft.inventory.ISidedInventory; 008import net.minecraft.item.Item; 009import net.minecraft.item.ItemPotion; 010import net.minecraft.item.ItemStack; 011import net.minecraft.nbt.NBTTagCompound; 012import net.minecraft.nbt.NBTTagList; 013import net.minecraft.potion.PotionHelper; 014 015public class TileEntityBrewingStand extends TileEntity implements ISidedInventory 016{ 017 private static final int[] field_102017_a = new int[] {3}; 018 private static final int[] field_102016_b = new int[] {0, 1, 2}; 019 020 /** The itemstacks currently placed in the slots of the brewing stand */ 021 private ItemStack[] brewingItemStacks = new ItemStack[4]; 022 private int brewTime; 023 024 /** 025 * an integer with each bit specifying whether that slot of the stand contains a potion 026 */ 027 private int filledSlots; 028 private int ingredientID; 029 private String field_94132_e; 030 031 /** 032 * Returns the name of the inventory. 033 */ 034 public String getInvName() 035 { 036 return this.isInvNameLocalized() ? this.field_94132_e : "container.brewing"; 037 } 038 039 /** 040 * If this returns false, the inventory name will be used as an unlocalized name, and translated into the player's 041 * language. Otherwise it will be used directly. 042 */ 043 public boolean isInvNameLocalized() 044 { 045 return this.field_94132_e != null && this.field_94132_e.length() > 0; 046 } 047 048 public void func_94131_a(String par1Str) 049 { 050 this.field_94132_e = par1Str; 051 } 052 053 /** 054 * Returns the number of slots in the inventory. 055 */ 056 public int getSizeInventory() 057 { 058 return this.brewingItemStacks.length; 059 } 060 061 /** 062 * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count 063 * ticks and creates a new spawn inside its implementation. 064 */ 065 public void updateEntity() 066 { 067 if (this.brewTime > 0) 068 { 069 --this.brewTime; 070 071 if (this.brewTime == 0) 072 { 073 this.brewPotions(); 074 this.onInventoryChanged(); 075 } 076 else if (!this.canBrew()) 077 { 078 this.brewTime = 0; 079 this.onInventoryChanged(); 080 } 081 else if (this.ingredientID != this.brewingItemStacks[3].itemID) 082 { 083 this.brewTime = 0; 084 this.onInventoryChanged(); 085 } 086 } 087 else if (this.canBrew()) 088 { 089 this.brewTime = 400; 090 this.ingredientID = this.brewingItemStacks[3].itemID; 091 } 092 093 int i = this.getFilledSlots(); 094 095 if (i != this.filledSlots) 096 { 097 this.filledSlots = i; 098 this.worldObj.setBlockMetadataWithNotify(this.xCoord, this.yCoord, this.zCoord, i, 2); 099 } 100 101 super.updateEntity(); 102 } 103 104 public int getBrewTime() 105 { 106 return this.brewTime; 107 } 108 109 private boolean canBrew() 110 { 111 if (this.brewingItemStacks[3] != null && this.brewingItemStacks[3].stackSize > 0) 112 { 113 ItemStack itemstack = this.brewingItemStacks[3]; 114 115 if (!Item.itemsList[itemstack.itemID].isPotionIngredient()) 116 { 117 return false; 118 } 119 else 120 { 121 boolean flag = false; 122 123 for (int i = 0; i < 3; ++i) 124 { 125 if (this.brewingItemStacks[i] != null && this.brewingItemStacks[i].itemID == Item.potion.itemID) 126 { 127 int j = this.brewingItemStacks[i].getItemDamage(); 128 int k = this.getPotionResult(j, itemstack); 129 130 if (!ItemPotion.isSplash(j) && ItemPotion.isSplash(k)) 131 { 132 flag = true; 133 break; 134 } 135 136 List list = Item.potion.getEffects(j); 137 List list1 = Item.potion.getEffects(k); 138 139 if ((j <= 0 || list != list1) && (list == null || !list.equals(list1) && list1 != null) && j != k) 140 { 141 flag = true; 142 break; 143 } 144 } 145 } 146 147 return flag; 148 } 149 } 150 else 151 { 152 return false; 153 } 154 } 155 156 private void brewPotions() 157 { 158 if (this.canBrew()) 159 { 160 ItemStack itemstack = this.brewingItemStacks[3]; 161 162 for (int i = 0; i < 3; ++i) 163 { 164 if (this.brewingItemStacks[i] != null && this.brewingItemStacks[i].itemID == Item.potion.itemID) 165 { 166 int j = this.brewingItemStacks[i].getItemDamage(); 167 int k = this.getPotionResult(j, itemstack); 168 List list = Item.potion.getEffects(j); 169 List list1 = Item.potion.getEffects(k); 170 171 if ((j <= 0 || list != list1) && (list == null || !list.equals(list1) && list1 != null)) 172 { 173 if (j != k) 174 { 175 this.brewingItemStacks[i].setItemDamage(k); 176 } 177 } 178 else if (!ItemPotion.isSplash(j) && ItemPotion.isSplash(k)) 179 { 180 this.brewingItemStacks[i].setItemDamage(k); 181 } 182 } 183 } 184 185 if (Item.itemsList[itemstack.itemID].hasContainerItem()) 186 { 187 this.brewingItemStacks[3] = Item.itemsList[itemstack.itemID].getContainerItemStack(brewingItemStacks[3]); 188 } 189 else 190 { 191 --this.brewingItemStacks[3].stackSize; 192 193 if (this.brewingItemStacks[3].stackSize <= 0) 194 { 195 this.brewingItemStacks[3] = null; 196 } 197 } 198 } 199 } 200 201 /** 202 * The result of brewing a potion of the specified damage value with an ingredient itemstack. 203 */ 204 private int getPotionResult(int par1, ItemStack par2ItemStack) 205 { 206 return par2ItemStack == null ? par1 : (Item.itemsList[par2ItemStack.itemID].isPotionIngredient() ? PotionHelper.applyIngredient(par1, Item.itemsList[par2ItemStack.itemID].getPotionEffect()) : par1); 207 } 208 209 /** 210 * Reads a tile entity from NBT. 211 */ 212 public void readFromNBT(NBTTagCompound par1NBTTagCompound) 213 { 214 super.readFromNBT(par1NBTTagCompound); 215 NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items"); 216 this.brewingItemStacks = new ItemStack[this.getSizeInventory()]; 217 218 for (int i = 0; i < nbttaglist.tagCount(); ++i) 219 { 220 NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i); 221 byte b0 = nbttagcompound1.getByte("Slot"); 222 223 if (b0 >= 0 && b0 < this.brewingItemStacks.length) 224 { 225 this.brewingItemStacks[b0] = ItemStack.loadItemStackFromNBT(nbttagcompound1); 226 } 227 } 228 229 this.brewTime = par1NBTTagCompound.getShort("BrewTime"); 230 231 if (par1NBTTagCompound.hasKey("CustomName")) 232 { 233 this.field_94132_e = par1NBTTagCompound.getString("CustomName"); 234 } 235 } 236 237 /** 238 * Writes a tile entity to NBT. 239 */ 240 public void writeToNBT(NBTTagCompound par1NBTTagCompound) 241 { 242 super.writeToNBT(par1NBTTagCompound); 243 par1NBTTagCompound.setShort("BrewTime", (short)this.brewTime); 244 NBTTagList nbttaglist = new NBTTagList(); 245 246 for (int i = 0; i < this.brewingItemStacks.length; ++i) 247 { 248 if (this.brewingItemStacks[i] != null) 249 { 250 NBTTagCompound nbttagcompound1 = new NBTTagCompound(); 251 nbttagcompound1.setByte("Slot", (byte)i); 252 this.brewingItemStacks[i].writeToNBT(nbttagcompound1); 253 nbttaglist.appendTag(nbttagcompound1); 254 } 255 } 256 257 par1NBTTagCompound.setTag("Items", nbttaglist); 258 259 if (this.isInvNameLocalized()) 260 { 261 par1NBTTagCompound.setString("CustomName", this.field_94132_e); 262 } 263 } 264 265 /** 266 * Returns the stack in slot i 267 */ 268 public ItemStack getStackInSlot(int par1) 269 { 270 return par1 >= 0 && par1 < this.brewingItemStacks.length ? this.brewingItemStacks[par1] : null; 271 } 272 273 /** 274 * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a 275 * new stack. 276 */ 277 public ItemStack decrStackSize(int par1, int par2) 278 { 279 if (par1 >= 0 && par1 < this.brewingItemStacks.length) 280 { 281 ItemStack itemstack = this.brewingItemStacks[par1]; 282 this.brewingItemStacks[par1] = null; 283 return itemstack; 284 } 285 else 286 { 287 return null; 288 } 289 } 290 291 /** 292 * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem - 293 * like when you close a workbench GUI. 294 */ 295 public ItemStack getStackInSlotOnClosing(int par1) 296 { 297 if (par1 >= 0 && par1 < this.brewingItemStacks.length) 298 { 299 ItemStack itemstack = this.brewingItemStacks[par1]; 300 this.brewingItemStacks[par1] = null; 301 return itemstack; 302 } 303 else 304 { 305 return null; 306 } 307 } 308 309 /** 310 * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections). 311 */ 312 public void setInventorySlotContents(int par1, ItemStack par2ItemStack) 313 { 314 if (par1 >= 0 && par1 < this.brewingItemStacks.length) 315 { 316 this.brewingItemStacks[par1] = par2ItemStack; 317 } 318 } 319 320 /** 321 * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't 322 * this more of a set than a get?* 323 */ 324 public int getInventoryStackLimit() 325 { 326 return 64; 327 } 328 329 /** 330 * Do not make give this method the name canInteractWith because it clashes with Container 331 */ 332 public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer) 333 { 334 return this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) <= 64.0D; 335 } 336 337 public void openChest() {} 338 339 public void closeChest() {} 340 341 /** 342 * Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot. 343 */ 344 public boolean isStackValidForSlot(int par1, ItemStack par2ItemStack) 345 { 346 return par1 == 3 ? Item.itemsList[par2ItemStack.itemID].isPotionIngredient() : par2ItemStack.itemID == Item.potion.itemID || par2ItemStack.itemID == Item.glassBottle.itemID; 347 } 348 349 @SideOnly(Side.CLIENT) 350 public void setBrewTime(int par1) 351 { 352 this.brewTime = par1; 353 } 354 355 /** 356 * returns an integer with each bit specifying wether that slot of the stand contains a potion 357 */ 358 public int getFilledSlots() 359 { 360 int i = 0; 361 362 for (int j = 0; j < 3; ++j) 363 { 364 if (this.brewingItemStacks[j] != null) 365 { 366 i |= 1 << j; 367 } 368 } 369 370 return i; 371 } 372 373 /** 374 * Get the size of the side inventory. 375 */ 376 public int[] getSizeInventorySide(int par1) 377 { 378 return par1 == 1 ? field_102017_a : field_102016_b; 379 } 380 381 public boolean func_102007_a(int par1, ItemStack par2ItemStack, int par3) 382 { 383 return this.isStackValidForSlot(par1, par2ItemStack); 384 } 385 386 public boolean func_102008_b(int par1, ItemStack par2ItemStack, int par3) 387 { 388 return true; 389 } 390}