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}