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}