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