package minefantasy.mf2.block.tileentity; import java.util.List; import java.util.Random; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import minefantasy.mf2.api.crafting.IBasicMetre; import minefantasy.mf2.api.heating.ForgeFuel; import minefantasy.mf2.api.heating.ForgeItemHandler; import minefantasy.mf2.api.heating.Heatable; import minefantasy.mf2.api.heating.IHotItem; import minefantasy.mf2.api.refine.Alloy; import minefantasy.mf2.api.refine.AlloyRecipes; import minefantasy.mf2.api.refine.IBellowsUseable; import minefantasy.mf2.api.refine.SmokeMechanics; import minefantasy.mf2.block.refining.BlockForge; import minefantasy.mf2.item.heatable.ItemHeated; import minefantasy.mf2.item.list.ComponentListMF; import minefantasy.mf2.network.packet.AnvilPacket; import minefantasy.mf2.network.packet.ForgePacket; import minefantasy.mf2.util.MFLogUtil; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityFurnace; import net.minecraft.util.StatCollector; import net.minecraft.world.WorldServer; public class TileEntityForge extends TileEntity implements IInventory, IBasicMetre, IBellowsUseable { public static final float dragonHeat = 200F; //200* private ItemStack[] inv = new ItemStack[1]; public float fuel; public float maxFuel = 6000;//5m public float temperature, fuelTemperature; public float maxTemperature = 1000; private Random rand = new Random(); private int ticksExisted; public float dragonHeartPower = 0F; public String texTypeForRender = "stone"; private boolean isBurning = false; public int workableState = 0; public TileEntityForge(Block block, String type) { texTypeForRender = type; blockType = block; blockMetadata = 0; } public TileEntityForge() { } @Override public void updateEntity() { if(worldObj.isRemote)return; if(justShared > 0)--justShared; super.updateEntity(); if(++ticksExisted % 20 == 0) { ItemStack item = getStackInSlot(0); if(item != null && !worldObj.isRemote) { modifyItem(item, 0); } syncData(); } if (ticksExisted % 10 == 0) { shareTemp(); } if(!isLit() && !worldObj.isRemote) { if(temperature > 0 && ticksExisted % 5 == 0) { temperature = 0; } return; } tickFuel(); if(fuel <= 0) { this.extinguish(); return; } isBurning = isBurning();//Check if it's burning float maxTemp = isLit() ? (fuelTemperature + getUnderTemperature()) : 0; if(temperature < maxTemp) { float amount = 0.2F; temperature += amount; if(temperature > maxTemp) { temperature = maxTemp; } } else if(temperature > maxTemp && rand.nextInt(20) == 0) { --temperature; } if(isBurning && temperature > 100 && rand.nextInt(20) == 0 && !isOutside()) { int val = this.getTier() == 1 ? 3 : 1; if(this.hasCrucibleAbove()) { SmokeMechanics.emitSmokeIndirect(worldObj, xCoord, yCoord+1, zCoord, val); } else { SmokeMechanics.emitSmokeIndirect(worldObj, xCoord, yCoord, zCoord, val); } } maxFuel = getTier() == 1 ? 12000 : 6000; } private boolean isOutside() { for(int x = -1; x <= 1; x++) { for(int y = -1; y <= 1; y++) { if(!worldObj.canBlockSeeTheSky(xCoord + x, yCoord+1, zCoord + y)) { return false; } } } return true; } public boolean isLit; private void shareTemp() { isLit = isLit(); shareTo(-1, 0); shareTo(1, 0); shareTo(0, -1); shareTo(0, 1); } private void shareTo(int x, int z) { if (fuel <= 0) return; int share = 2; TileEntity tile = worldObj.getTileEntity(xCoord + x, yCoord, zCoord + z); if (tile == null) return; if (tile instanceof TileEntityForge) { TileEntityForge forge = (TileEntityForge) tile; if (isLit && !forge.isLit && forge.fuel > 0) { forge.fireUpForge(); } if (!forge.isBurning() && temperature > 1) { forge.temperature = 1; } if (forge.temperature < (temperature - share)) { forge.temperature += share; temperature -= share; } share = 1200; if (forge.fuel < (fuel - share)) { forge.fuel += share; fuel -= share; } } } private void tickFuel() { if(fuel > 0) { fuel -= 0.2F; } if(fuel < 0)fuel = 0; } private boolean isBurning() { return fuel > 0 && temperature > 0; } @SideOnly(Side.CLIENT) private boolean shouldRenderFlame() { return fuel > 0 && temperature > 1; } private void modifyItem(ItemStack item, int slot) { if(item.getItem() == ComponentListMF.hotItem) { int temp = ItemHeated.getTemp(item); if(temp > temperature) { int i = (int)(temperature/5F); temp -= i; } else { int increase = (int)(temperature / (20F*getStackModifier(item.stackSize))); if(temp >= (temperature-increase)) { temp = (int) temperature; } else { temp += increase; } } if(temp <= 0) { this.setInventorySlotContents(slot, ItemHeated.getItem(item)); } else { ItemHeated.setTemp(item, Math.max(0, temp)); } } else if(temperature > 0) { ItemStack heated = ItemHeated.createHotItem(item); this.setInventorySlotContents(slot, ItemHeated.createHotItem(item)); } } private float getStackModifier(int stackSize) { float mod = 1F + (float)stackSize / 8F;//1x to 9x MFLogUtil.logDebug("HeatModifier: " + mod); return mod; } public int getTier() { Block block = worldObj.getBlock(xCoord, yCoord, zCoord); if(block != null && block instanceof BlockForge) { return ((BlockForge)block).tier; } return 0; } public float getUnderTemperature() { Block under = worldObj.getBlock(xCoord, yCoord-1, zCoord); if(under.getMaterial() == Material.fire) { return 50F; } if(under.getMaterial() == Material.lava) { return 100F; } return 0F; } @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); nbt.setFloat("temperature", temperature); nbt.setFloat("fuelTemperature", fuelTemperature); nbt.setFloat("dragonHeartPower", dragonHeartPower); nbt.setFloat("fuel", fuel); nbt.setFloat("maxFuel", maxFuel); NBTTagList savedItems = new NBTTagList(); for (int i = 0; i < this.inv.length; ++i) { if (this.inv[i] != null) { NBTTagCompound savedSlot = new NBTTagCompound(); savedSlot.setByte("Slot", (byte)i); this.inv[i].writeToNBT(savedSlot); savedItems.appendTag(savedSlot); } } nbt.setTag("Items", savedItems); } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); temperature = nbt.getFloat("temperature"); fuelTemperature = nbt.getFloat("fuelTemperature"); dragonHeartPower = nbt.getFloat("dragonHeartPower"); fuel = nbt.getFloat("fuel"); maxFuel = nbt.getFloat("maxFuel"); NBTTagList savedItems = nbt.getTagList("Items", 10); this.inv = new ItemStack[this.getSizeInventory()]; for (int i = 0; i < savedItems.tagCount(); ++i) { NBTTagCompound savedSlot = savedItems.getCompoundTagAt(i); byte slotNum = savedSlot.getByte("Slot"); if (slotNum >= 0 && slotNum < this.inv.length) { this.inv[slotNum] = ItemStack.loadItemStackFromNBT(savedSlot); } } } //INVENTORY @Override public int getSizeInventory() { return inv.length; } @Override public ItemStack getStackInSlot(int slot) { return inv[slot]; } @Override public ItemStack decrStackSize(int slot, int num) { onInventoryChanged(); if (this.inv[slot] != null) { ItemStack itemstack; if (this.inv[slot].stackSize <= num) { itemstack = this.inv[slot]; this.inv[slot] = null; return itemstack; } else { itemstack = this.inv[slot].splitStack(num); if (this.inv[slot].stackSize == 0) { this.inv[slot] = null; } return itemstack; } } else { return null; } } @Override public ItemStack getStackInSlotOnClosing(int slot) { return inv[slot]; } @Override public void setInventorySlotContents(int slot, ItemStack item) { onInventoryChanged(); inv[slot] = item; } public void onInventoryChanged() { } @Override public String getInventoryName() { return "gui.crucible.name"; } @Override public boolean hasCustomInventoryName() { return false; } @Override public int getInventoryStackLimit() { return 64; } @Override public boolean isUseableByPlayer(EntityPlayer user) { return user.getDistance(xCoord+0.5D, yCoord+0.5D, zCoord+0.5D) < 8D; } @Override public void openInventory() { } @Override public void closeInventory() { } @Override public boolean isItemValidForSlot(int slot, ItemStack item) { return true; } public BlockForge getActiveBlock() { if(worldObj == null)return null; Block block = worldObj.getBlock(xCoord, yCoord, zCoord); if(block != null && block instanceof BlockForge) { return (BlockForge)block; } return null; } @SideOnly(Side.CLIENT) public String getTextureName() { BlockForge forge = getActiveBlock(); if(forge == null)return "forge_"+texTypeForRender; return "forge_" + forge.type + (shouldRenderFlame() ? "_active" : ""); } public boolean hasFuel() { return worldObj != null && fuel > 0; } public boolean isLit() { BlockForge forge = getActiveBlock(); return forge != null && forge.isActive; } /** * Puts the fire out */ public void extinguish() { if(getTier() == 1) { return; } BlockForge.updateFurnaceBlockState(false, worldObj, xCoord, yCoord, zCoord); } /** * Fires the forge up */ public void fireUpForge() { if(getTier() == 1) { return; } BlockForge.updateFurnaceBlockState(true, worldObj, xCoord, yCoord, zCoord); } public float getBellowsEffect() { return getTier() == 1 ? 2.0F : 1.5F; } private float getBellowsMax() { return Math.min(fuelTemperature*getBellowsEffect(), getMaxTemp()); } public int getMaxTemp() { return 1000; } public boolean addFuel(ForgeFuel stats, boolean hand, int tier) { maxFuel = tier == 1 ? 12000 : 6000; boolean hasUsed = false; if(stats.baseHeat > this.fuelTemperature) // uses if hotter { hasUsed = true; } int room_left = (int) (maxFuel - fuel); if(hand && room_left > 0) { hasUsed = true; fuel = Math.min(fuel + stats.duration, maxFuel);//Fill as much as can fit } else if(!hand && (fuel == 0 || room_left >= stats.duration))//For hoppers: only fill when there's full room { hasUsed = true; fuel = Math.min(fuel + stats.duration, maxFuel);//Fill as much as can fit } if(stats.doesLight && !isLit()) { fireUpForge(); hasUsed = true; } if(hasUsed) { fuelTemperature = stats.baseHeat; } return hasUsed; } @Override public int getMetreScale(int size) { if(shouldShowMetre()) { return (int)((float)size / maxFuel * fuel); } return 0; } public int[] getTempsScaled(int size) { int[] temps = new int[2]; if(shouldShowMetre()) { temps[0] = (int)((float)size / this.maxTemperature * this.temperature); temps[1] = (int)((float)size / this.maxTemperature * this.fuelTemperature); } if(temps[0] > size)temps[0] = size; if(temps[1] > size)temps[1] = size; return temps; } @Override public boolean shouldShowMetre() { return true; } @Override public String getLocalisedName() { return StatCollector.translateToLocal(workableState >= 2 ? "state.unstable" : workableState == 1 ? "state.workable" : "forge.fuel.name"); } public boolean[] showSides() { if (worldObj == null) { return new boolean[] { true, true, true, true }; } boolean front = !isForge(0, 0, 1); boolean left = !isForge(-1, 0, 0); boolean right = !isForge(1, 0, 0); boolean back = !isForge(0, 0, -1); return new boolean[] { front, left, right, back }; } private boolean isForge(int x, int y, int z) { return worldObj.getBlock(xCoord + x, yCoord + y, zCoord + z) instanceof BlockForge; } public void syncData() { if(worldObj.isRemote)return; List<EntityPlayer> players = ((WorldServer)worldObj).playerEntities; for(int i = 0; i < players.size(); i++) { EntityPlayer player = players.get(i); ((WorldServer)worldObj).getEntityTracker().func_151248_b(player, new ForgePacket(this).generatePacket()); } } int justShared; public void onUsedWithBellows(float powerLevel) { if(!isBurning())return; if(justShared > 0) { return; } if(fuel <= 0) { return; } float max = getBellowsMax(); justShared = 5; if(temperature < max) { temperature = Math.min(max, temperature + (50F*powerLevel)); } for(int a = 0; a < 10; a ++) { worldObj.spawnParticle("flame", xCoord+(rand.nextDouble()*0.8D)+0.1D, yCoord + 0.4D, zCoord+(rand.nextDouble()*0.8D)+0.1D, 0, 0.01, 0); } pumpBellows(-1, 0, powerLevel*0.9F); pumpBellows(0, -1, powerLevel*0.9F); pumpBellows(0, 1, powerLevel*0.9F); pumpBellows(1, 0, powerLevel*0.9F); } private void pumpBellows(int x, int z, float pump) { if(fuel <= 0)return; int share = 2; TileEntity tile = worldObj.getTileEntity(xCoord+x, yCoord, zCoord+z); if(tile == null)return; if(tile instanceof TileEntityForge) { TileEntityForge forge = (TileEntityForge)tile; forge.onUsedWithBellows(pump); } } public float getBlockTemperature() { if(this.isLit) { return temperature; } return 0; } public boolean hasCrucibleAbove() { if(worldObj == null)return false; TileEntity tile = worldObj.getTileEntity(xCoord, yCoord+1, zCoord); return tile != null && tile instanceof TileEntityCrucible || tile instanceof TileEntityFurnace; } private void averageAllItems() { /* int temp = 0; int items = 0; for(ItemStack item: inv) { if(item != null && item.getItem() instanceof IHotItem) { ++items; temp += ItemHeated.getTemp(item); } } int average = (int)((float)temp / items); for(ItemStack item: inv) { if(item != null && item.getItem() instanceof IHotItem) { ItemHeated.setTemp(item, average); } } */ } public boolean tryAddHeatable(ItemStack held) { ItemStack contents = inv[0]; if(contents == null) { ItemStack placed = held.copy(); placed.stackSize = 1; setInventorySlotContents(0, placed); return true; } else if(contents.getItem() instanceof ItemHeated) { ItemStack hot = Heatable.getItem(contents); if(hot != null && hot.isItemEqual(held) && contents.stackSize < contents.getMaxStackSize()) { contents.stackSize ++; return true; } } return false; } public int getWorkableState() { if(worldObj == null || worldObj.isRemote) { return workableState; } if(this.inv[0] != null) { return (int)Heatable.getHeatableStage(inv[0]); } return 0; } }