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 }