    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    }