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).func_77861_e().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 }