001    package net.minecraft.src;
002    
003    import net.minecraftforge.common.ISidedInventory;
004    import net.minecraftforge.common.ForgeDirection;
005    import cpw.mods.fml.common.registry.GameRegistry;
006    
007    import cpw.mods.fml.common.Side;
008    import cpw.mods.fml.common.asm.SideOnly;
009    
010    public class TileEntityFurnace extends TileEntity implements IInventory, ISidedInventory
011    {
012        /**
013         * The ItemStacks that hold the items currently being used in the furnace
014         */
015        private ItemStack[] furnaceItemStacks = new ItemStack[3];
016    
017        /** The number of ticks that the furnace will keep burning */
018        public int furnaceBurnTime = 0;
019    
020        /**
021         * The number of ticks that a fresh copy of the currently-burning item would keep the furnace burning for
022         */
023        public int currentItemBurnTime = 0;
024    
025        /** The number of ticks that the current item has been cooking for */
026        public int furnaceCookTime = 0;
027    
028        /**
029         * Returns the number of slots in the inventory.
030         */
031        public int getSizeInventory()
032        {
033            return this.furnaceItemStacks.length;
034        }
035    
036        /**
037         * Returns the stack in slot i
038         */
039        public ItemStack getStackInSlot(int par1)
040        {
041            return this.furnaceItemStacks[par1];
042        }
043    
044        /**
045         * Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
046         * new stack.
047         */
048        public ItemStack decrStackSize(int par1, int par2)
049        {
050            if (this.furnaceItemStacks[par1] != null)
051            {
052                ItemStack var3;
053    
054                if (this.furnaceItemStacks[par1].stackSize <= par2)
055                {
056                    var3 = this.furnaceItemStacks[par1];
057                    this.furnaceItemStacks[par1] = null;
058                    return var3;
059                }
060                else
061                {
062                    var3 = this.furnaceItemStacks[par1].splitStack(par2);
063    
064                    if (this.furnaceItemStacks[par1].stackSize == 0)
065                    {
066                        this.furnaceItemStacks[par1] = null;
067                    }
068    
069                    return var3;
070                }
071            }
072            else
073            {
074                return null;
075            }
076        }
077    
078        /**
079         * When some containers are closed they call this on each slot, then drop whatever it returns as an EntityItem -
080         * like when you close a workbench GUI.
081         */
082        public ItemStack getStackInSlotOnClosing(int par1)
083        {
084            if (this.furnaceItemStacks[par1] != null)
085            {
086                ItemStack var2 = this.furnaceItemStacks[par1];
087                this.furnaceItemStacks[par1] = null;
088                return var2;
089            }
090            else
091            {
092                return null;
093            }
094        }
095    
096        /**
097         * Sets the given item stack to the specified slot in the inventory (can be crafting or armor sections).
098         */
099        public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
100        {
101            this.furnaceItemStacks[par1] = par2ItemStack;
102    
103            if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
104            {
105                par2ItemStack.stackSize = this.getInventoryStackLimit();
106            }
107        }
108    
109        /**
110         * Returns the name of the inventory.
111         */
112        public String getInvName()
113        {
114            return "container.furnace";
115        }
116    
117        /**
118         * Reads a tile entity from NBT.
119         */
120        public void readFromNBT(NBTTagCompound par1NBTTagCompound)
121        {
122            super.readFromNBT(par1NBTTagCompound);
123            NBTTagList var2 = par1NBTTagCompound.getTagList("Items");
124            this.furnaceItemStacks = new ItemStack[this.getSizeInventory()];
125    
126            for (int var3 = 0; var3 < var2.tagCount(); ++var3)
127            {
128                NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
129                byte var5 = var4.getByte("Slot");
130    
131                if (var5 >= 0 && var5 < this.furnaceItemStacks.length)
132                {
133                    this.furnaceItemStacks[var5] = ItemStack.loadItemStackFromNBT(var4);
134                }
135            }
136    
137            this.furnaceBurnTime = par1NBTTagCompound.getShort("BurnTime");
138            this.furnaceCookTime = par1NBTTagCompound.getShort("CookTime");
139            this.currentItemBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
140        }
141    
142        /**
143         * Writes a tile entity to NBT.
144         */
145        public void writeToNBT(NBTTagCompound par1NBTTagCompound)
146        {
147            super.writeToNBT(par1NBTTagCompound);
148            par1NBTTagCompound.setShort("BurnTime", (short)this.furnaceBurnTime);
149            par1NBTTagCompound.setShort("CookTime", (short)this.furnaceCookTime);
150            NBTTagList var2 = new NBTTagList();
151    
152            for (int var3 = 0; var3 < this.furnaceItemStacks.length; ++var3)
153            {
154                if (this.furnaceItemStacks[var3] != null)
155                {
156                    NBTTagCompound var4 = new NBTTagCompound();
157                    var4.setByte("Slot", (byte)var3);
158                    this.furnaceItemStacks[var3].writeToNBT(var4);
159                    var2.appendTag(var4);
160                }
161            }
162    
163            par1NBTTagCompound.setTag("Items", var2);
164        }
165    
166        /**
167         * Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
168         * this more of a set than a get?*
169         */
170        public int getInventoryStackLimit()
171        {
172            return 64;
173        }
174    
175        @SideOnly(Side.CLIENT)
176    
177        /**
178         * Returns an integer between 0 and the passed value representing how close the current item is to being completely
179         * cooked
180         */
181        public int getCookProgressScaled(int par1)
182        {
183            return this.furnaceCookTime * par1 / 200;
184        }
185    
186        @SideOnly(Side.CLIENT)
187    
188        /**
189         * Returns an integer between 0 and the passed value representing how much burn time is left on the current fuel
190         * item, where 0 means that the item is exhausted and the passed value means that the item is fresh
191         */
192        public int getBurnTimeRemainingScaled(int par1)
193        {
194            if (this.currentItemBurnTime == 0)
195            {
196                this.currentItemBurnTime = 200;
197            }
198    
199            return this.furnaceBurnTime * par1 / this.currentItemBurnTime;
200        }
201    
202        /**
203         * Returns true if the furnace is currently burning
204         */
205        public boolean isBurning()
206        {
207            return this.furnaceBurnTime > 0;
208        }
209    
210        /**
211         * Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
212         * ticks and creates a new spawn inside its implementation.
213         */
214        public void updateEntity()
215        {
216            boolean var1 = this.furnaceBurnTime > 0;
217            boolean var2 = false;
218    
219            if (this.furnaceBurnTime > 0)
220            {
221                --this.furnaceBurnTime;
222            }
223    
224            if (!this.worldObj.isRemote)
225            {
226                if (this.furnaceBurnTime == 0 && this.canSmelt())
227                {
228                    this.currentItemBurnTime = this.furnaceBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
229    
230                    if (this.furnaceBurnTime > 0)
231                    {
232                        var2 = true;
233    
234                        if (this.furnaceItemStacks[1] != null)
235                        {
236                            --this.furnaceItemStacks[1].stackSize;
237    
238                            if (this.furnaceItemStacks[1].stackSize == 0)
239                            {
240                                this.furnaceItemStacks[1] = this.furnaceItemStacks[1].getItem().getContainerItemStack(furnaceItemStacks[1]);
241                            }
242                        }
243                    }
244                }
245    
246                if (this.isBurning() && this.canSmelt())
247                {
248                    ++this.furnaceCookTime;
249    
250                    if (this.furnaceCookTime == 200)
251                    {
252                        this.furnaceCookTime = 0;
253                        this.smeltItem();
254                        var2 = true;
255                    }
256                }
257                else
258                {
259                    this.furnaceCookTime = 0;
260                }
261    
262                if (var1 != this.furnaceBurnTime > 0)
263                {
264                    var2 = true;
265                    BlockFurnace.updateFurnaceBlockState(this.furnaceBurnTime > 0, this.worldObj, this.xCoord, this.yCoord, this.zCoord);
266                }
267            }
268    
269            if (var2)
270            {
271                this.onInventoryChanged();
272            }
273        }
274    
275        /**
276         * Returns true if the furnace can smelt an item, i.e. has a source item, destination stack isn't full, etc.
277         */
278        private boolean canSmelt()
279        {
280            if (this.furnaceItemStacks[0] == null)
281            {
282                return false;
283            }
284            else
285            {
286                ItemStack var1 = FurnaceRecipes.smelting().getSmeltingResult(this.furnaceItemStacks[0]);
287                if (var1 == null) return false;
288                if (this.furnaceItemStacks[2] == null) return true;
289                if (!this.furnaceItemStacks[2].isItemEqual(var1)) return false;
290                int result = furnaceItemStacks[2].stackSize + var1.stackSize;
291                return (result <= getInventoryStackLimit() && result <= var1.getMaxStackSize());
292            }
293        }
294    
295        /**
296         * Turn one item from the furnace source stack into the appropriate smelted item in the furnace result stack
297         */
298        public void smeltItem()
299        {
300            if (this.canSmelt())
301            {
302                ItemStack var1 = FurnaceRecipes.smelting().getSmeltingResult(this.furnaceItemStacks[0]);
303    
304                if (this.furnaceItemStacks[2] == null)
305                {
306                    this.furnaceItemStacks[2] = var1.copy();
307                }
308                else if (this.furnaceItemStacks[2].isItemEqual(var1))
309                {
310                    furnaceItemStacks[2].stackSize += var1.stackSize;
311                }
312    
313                --this.furnaceItemStacks[0].stackSize;
314    
315                if (this.furnaceItemStacks[0].stackSize <= 0)
316                {
317                    this.furnaceItemStacks[0] = null;
318                }
319            }
320        }
321    
322        /**
323         * Returns the number of ticks that the supplied fuel item will keep the furnace burning, or 0 if the item isn't
324         * fuel
325         */
326        public static int getItemBurnTime(ItemStack par0ItemStack)
327        {
328            if (par0ItemStack == null)
329            {
330                return 0;
331            }
332            else
333            {
334                int var1 = par0ItemStack.getItem().shiftedIndex;
335                Item var2 = par0ItemStack.getItem();
336    
337                if (par0ItemStack.getItem() instanceof ItemBlock && Block.blocksList[var1] != null)
338                {
339                    Block var3 = Block.blocksList[var1];
340    
341                    if (var3 == Block.woodSingleSlab)
342                    {
343                        return 150;
344                    }
345    
346                    if (var3.blockMaterial == Material.wood)
347                    {
348                        return 300;
349                    }
350                }
351                if (var2 instanceof ItemTool && ((ItemTool) var2).getToolMaterialName().equals("WOOD")) return 200;
352                if (var2 instanceof ItemSword && ((ItemSword) var2).func_77825_f().equals("WOOD")) return 200;
353                if (var2 instanceof ItemHoe && ((ItemHoe) var2).func_77842_f().equals("WOOD")) return 200;
354                if (var1 == Item.stick.shiftedIndex) return 100;
355                if (var1 == Item.coal.shiftedIndex) return 1600;
356                if (var1 == Item.bucketLava.shiftedIndex) return 20000;
357                if (var1 == Block.sapling.blockID) return 100;
358                if (var1 == Item.blazeRod.shiftedIndex) return 2400;
359                return GameRegistry.getFuelValue(par0ItemStack);
360            }
361        }
362    
363        /**
364         * Return true if item is a fuel source (getItemBurnTime() > 0).
365         */
366        public static boolean isItemFuel(ItemStack par0ItemStack)
367        {
368            return getItemBurnTime(par0ItemStack) > 0;
369        }
370    
371        /**
372         * Do not make give this method the name canInteractWith because it clashes with Container
373         */
374        public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
375        {
376            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;
377        }
378    
379        public void openChest() {}
380    
381        public void closeChest() {}
382    
383        @Override
384        public int getStartInventorySide(ForgeDirection side)
385        {
386            if (side == ForgeDirection.DOWN) return 1;
387            if (side == ForgeDirection.UP) return 0; 
388            return 2;
389        }
390    
391        @Override
392        public int getSizeInventorySide(ForgeDirection side)
393        {
394            return 1;
395        }
396    }