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